diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index c1a46b22e..a1a911edd 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -1200,11 +1200,11 @@ void ConnectionsManager::processServerResponse(TLObject *message, int64_t messag bool ignoreResult = false; if (hasResult) { TLObject *object = response->result.get(); - if (LOGS_ENABLED) DEBUG_D("connection(%p, account%u, dc%u, type %d) received rpc_result with %s", connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), typeid(*object).name()); + if (LOGS_ENABLED) DEBUG_D("message_id %lld connection(%p, account%u, dc%u, type %d) received rpc_result with %s", messageId, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), typeid(*object).name()); } RpcError *error = hasResult ? dynamic_cast(response->result.get()) : nullptr; if (error != nullptr) { - if (LOGS_ENABLED) DEBUG_E("connection(%p, account%u, dc%u, type %d) rpc error %d: %s", connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), error->error_code, error->error_message.c_str()); + if (LOGS_ENABLED) DEBUG_E("message_id %lld connection(%p, account%u, dc%u, type %d) rpc error %d: %s", messageId, connection, instanceNum, datacenter->getDatacenterId(), connection->getConnectionType(), error->error_code, error->error_message.c_str()); if (error->error_code == 303) { uint32_t migrateToDatacenterId = DEFAULT_DATACENTER_ID; diff --git a/TMessagesProj/src/main/assets/night.attheme b/TMessagesProj/src/main/assets/night.attheme index f52de5258..2adf980b2 100644 --- a/TMessagesProj/src/main/assets/night.attheme +++ b/TMessagesProj/src/main/assets/night.attheme @@ -127,6 +127,7 @@ listSelector=771751936 chat_outPreviewInstantText=-1 chat_inMenuSelected=-1517440301 avatar_backgroundOrange=-869276 +avatar_background2Orange=-1734333 avatar_actionBarSelectorGreen=-12758164 chat_outLocationIcon=-1 chat_inLoaderSelected=-11297295 @@ -155,6 +156,7 @@ chat_messageTextOut=-328966 chat_inInstant=-8796932 groupcreate_cursor=-10177041 avatar_backgroundSaved=-11558424 +avatar_background2Saved=-15038233 returnToCallBackground=-10639897 checkboxSquareUnchecked=-11245959 dialogCheckboxSquareDisabled=-12040120 @@ -201,6 +203,7 @@ calls_callReceivedGreenIcon=-12001930 chats_pinnedOverlay=201326591 windowBackgroundWhiteInputField=-11513776 avatar_backgroundRed=-2326437 +avatar_background2Red=-2863816 statisticChartLine_green=-12729793 chat_emojiPanelIconSelector=-10177041 chat_emojiPanelBadgeBackground=-11291403 diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 0a6f6bc35..926d02169 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -24,8 +24,8 @@ public class BuildVars { public static boolean USE_CLOUD_STRINGS = true; public static boolean CHECK_UPDATES = true; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; - public static int BUILD_VERSION = 2902; - public static String BUILD_VERSION_STRING = "9.1.2"; + public static int BUILD_VERSION = 2917; + public static String BUILD_VERSION_STRING = "9.1.3"; public static int APP_ID = 4; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueuePoolBackground.java b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueuePoolBackground.java index 0788fadf4..8b628ac81 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueuePoolBackground.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueuePoolBackground.java @@ -18,6 +18,7 @@ public class DispatchQueuePoolBackground { private int totalTasksCount; private boolean cleanupScheduled; + public static final String THREAD_PREFIX = "DispatchQueuePoolThreadSafety_"; static ArrayList updateTaskCollection; private static DispatchQueuePoolBackground backgroundQueue; @@ -62,7 +63,7 @@ public class DispatchQueuePoolBackground { if (!busyQueues.isEmpty() && (totalTasksCount / 2 <= busyQueues.size() || queues.isEmpty() && createdCount >= maxCount)) { queue = busyQueues.remove(0); } else if (queues.isEmpty()) { - queue = new DispatchQueue("DispatchQueuePoolThreadSafety" + guid + "_" + Utilities.random.nextInt()); + queue = new DispatchQueue(THREAD_PREFIX + guid + "_" + Utilities.random.nextInt()); queue.setPriority(Thread.MAX_PRIORITY); createdCount++; } else { @@ -104,6 +105,10 @@ public class DispatchQueuePoolBackground { @UiThread public static void execute(Runnable runnable) { + execute(runnable, false); + } + @UiThread + public static void execute(Runnable runnable, boolean now) { if (BuildVars.DEBUG_PRIVATE_VERSION && Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { throw new RuntimeException("wrong thread"); } @@ -113,10 +118,16 @@ public class DispatchQueuePoolBackground { } else { updateTaskCollection = new ArrayList<>(100); } - AndroidUtilities.runOnUIThread(finishCollectUpdateRunnable); + if (!now) { + AndroidUtilities.runOnUIThread(finishCollectUpdateRunnable); + } } updateTaskCollection.add(runnable); + if (now) { + AndroidUtilities.cancelRunOnUIThread(finishCollectUpdateRunnable); + finishCollectUpdateRunnable.run(); + } } private static void finishCollectUpdateRunnables() { @@ -127,7 +138,7 @@ public class DispatchQueuePoolBackground { ArrayList arrayList = updateTaskCollection; updateTaskCollection = null; if (backgroundQueue == null) { - backgroundQueue = new DispatchQueuePoolBackground(Math.max(1, Runtime.getRuntime().availableProcessors() - 2)); + backgroundQueue = new DispatchQueuePoolBackground(Math.max(1, Runtime.getRuntime().availableProcessors())); } Utilities.globalQueue.postRunnable(() -> { backgroundQueue.execute(arrayList); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index d72924dbc..3681d9c60 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -1281,114 +1281,127 @@ public class FileLoadOperation { if (BuildVars.DEBUG_VERSION) { FileLog.d("finished preloading file to " + cacheFileTemp + " loaded " + totalPreloadedBytes + " of " + totalBytesCount); } + delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal); } else { - if (cacheIvTemp != null) { - cacheIvTemp.delete(); - cacheIvTemp = null; - } - if (cacheFileParts != null) { - cacheFileParts.delete(); - cacheFileParts = null; - } - if (cacheFilePreload != null) { - cacheFilePreload.delete(); - cacheFilePreload = null; - } - if (cacheFileTemp != null) { - if (ungzip) { - try { - GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(cacheFileTemp)); - FileLoader.copyFile(gzipInputStream, cacheFileGzipTemp, 1024 * 1024 * 2); - gzipInputStream.close(); - cacheFileTemp.delete(); - cacheFileTemp = cacheFileGzipTemp; - ungzip = false; - } catch (ZipException zipException) { - ungzip = false; - } catch (Throwable e) { - FileLog.e(e); - if (BuildVars.LOGS_ENABLED) { - FileLog.e("unable to ungzip temp = " + cacheFileTemp + " to final = " + cacheFileFinal); + final File cacheIvTempFinal = cacheIvTemp; + final File cacheFilePartsFinal = cacheFileParts; + final File cacheFilePreloadFinal = cacheFilePreload; + final File cacheFileTempFinal = cacheFileTemp; + Utilities.globalQueue.postRunnable(() -> { + if (cacheIvTempFinal != null) { + cacheIvTempFinal.delete(); + } + if (cacheFilePartsFinal != null) { + cacheFilePartsFinal.delete(); + } + if (cacheFilePreloadFinal != null) { + cacheFilePreloadFinal.delete(); + } + File cacheFileTempLocal = cacheFileTempFinal; + if (cacheFileTempLocal != null) { + if (ungzip) { + try { + GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(cacheFileTempLocal)); + FileLoader.copyFile(gzipInputStream, cacheFileGzipTemp, 1024 * 1024 * 2); + gzipInputStream.close(); + cacheFileTempLocal.delete(); + cacheFileTempLocal = cacheFileGzipTemp; + ungzip = false; + } catch (ZipException zipException) { + ungzip = false; + } catch (Throwable e) { + FileLog.e(e); + if (BuildVars.LOGS_ENABLED) { + FileLog.e("unable to ungzip temp = " + cacheFileTempFinal + " to final = " + cacheFileFinal); + } } } - } - if (!ungzip) { - boolean renameResult; - if (parentObject instanceof TLRPC.TL_theme) { - try { - renameResult = AndroidUtilities.copyFile(cacheFileTemp, cacheFileFinal); - } catch (Exception e) { - renameResult = false; - FileLog.e(e); - } - } else { - try { - if (pathSaveData != null) { - synchronized (lockObject) { - cacheFileFinal = new File(storePath, storeFileName); - int count = 1; - while (cacheFileFinal.exists()) { - int lastDotIndex = storeFileName.lastIndexOf('.'); - String newFileName; - if (lastDotIndex > 0) { - newFileName = storeFileName.substring(0, lastDotIndex) + " (" + count + ")" + storeFileName.substring(lastDotIndex); - } else { - newFileName = storeFileName + " (" + count + ")"; + if (!ungzip) { + boolean renameResult; + if (parentObject instanceof TLRPC.TL_theme) { + try { + renameResult = AndroidUtilities.copyFile(cacheFileTempLocal, cacheFileFinal); + } catch (Exception e) { + renameResult = false; + FileLog.e(e); + } + } else { + try { + if (pathSaveData != null) { + synchronized (lockObject) { + cacheFileFinal = new File(storePath, storeFileName); + int count = 1; + while (cacheFileFinal.exists()) { + int lastDotIndex = storeFileName.lastIndexOf('.'); + String newFileName; + if (lastDotIndex > 0) { + newFileName = storeFileName.substring(0, lastDotIndex) + " (" + count + ")" + storeFileName.substring(lastDotIndex); + } else { + newFileName = storeFileName + " (" + count + ")"; + } + cacheFileFinal = new File(storePath, newFileName); + count++; } - cacheFileFinal = new File(storePath, newFileName); - count++; } } + renameResult = cacheFileTempLocal.renameTo(cacheFileFinal); + } catch (Exception e) { + renameResult = false; + FileLog.e(e); } - renameResult = cacheFileTemp.renameTo(cacheFileFinal); - } catch (Exception e) { - renameResult = false; - FileLog.e(e); } - } - if (!renameResult) { - if (BuildVars.LOGS_ENABLED) { - FileLog.e("unable to rename temp = " + cacheFileTemp + " to final = " + cacheFileFinal + " retry = " + renameRetryCount); + if (!renameResult) { + if (BuildVars.LOGS_ENABLED) { + FileLog.e("unable to rename temp = " + cacheFileTempLocal + " to final = " + cacheFileFinal + " retry = " + renameRetryCount); + } + renameRetryCount++; + if (renameRetryCount < 3) { + state = stateDownloading; + Utilities.stageQueue.postRunnable(() -> { + try { + onFinishLoadingFile(increment); + } catch (Exception e) { + onFail(false, 0); + } + }, 200); + return; + } + cacheFileFinal = cacheFileTempLocal; + } else { + if (pathSaveData != null && cacheFileFinal.exists()) { + delegate.saveFilePath(pathSaveData, cacheFileFinal); + } } - renameRetryCount++; - if (renameRetryCount < 3) { - state = stateDownloading; - Utilities.stageQueue.postRunnable(() -> { - try { - onFinishLoadingFile(increment); - } catch (Exception e) { - onFail(false, 0); - } - }, 200); - return; - } - cacheFileFinal = cacheFileTemp; } else { - if (pathSaveData != null && cacheFileFinal.exists()) { - delegate.saveFilePath(pathSaveData, cacheFileFinal); + Utilities.stageQueue.postRunnable(() -> { + onFail(false, 0); + }); + return; + } + } + Utilities.stageQueue.postRunnable(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("finished downloading file to " + cacheFileFinal + " time = " + (System.currentTimeMillis() - startTime)); + } + if (increment) { + if (currentType == ConnectionsManager.FileTypeAudio) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_AUDIOS, 1); + } else if (currentType == ConnectionsManager.FileTypeVideo) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_VIDEOS, 1); + } else if (currentType == ConnectionsManager.FileTypePhoto) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); + } else if (currentType == ConnectionsManager.FileTypeFile) { + StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); } } - } else { - onFail(false, 0); - return; - } - } - if (BuildVars.LOGS_ENABLED) { - FileLog.d("finished downloading file to " + cacheFileFinal + " time = " + (System.currentTimeMillis() - startTime)); - } - if (increment) { - if (currentType == ConnectionsManager.FileTypeAudio) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_AUDIOS, 1); - } else if (currentType == ConnectionsManager.FileTypeVideo) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_VIDEOS, 1); - } else if (currentType == ConnectionsManager.FileTypePhoto) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1); - } else if (currentType == ConnectionsManager.FileTypeFile) { - StatsController.getInstance(currentAccount).incrementReceivedItemsCount(ApplicationLoader.getCurrentNetworkType(), StatsController.TYPE_FILES, 1); - } - } + delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal); + }); + }); + cacheIvTemp = null; + cacheFileParts = null; + cacheFilePreload = null; } - delegate.didFinishLoadingFile(FileLoadOperation.this, cacheFileFinal); + } private void delayRequestInfo(RequestInfo requestInfo) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java index a3ef6b079..b87283fbf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java @@ -92,6 +92,7 @@ public class FileLog { try { String metadata = "requestMsgId=" + requestMsgId + " requestingTime=" + (System.currentTimeMillis() - startRequestTimeInMillis) + " request_token=" + requestToken; FileLog.getInstance().tlStreamWriter.write(getInstance().dateFormat.format(time) + " " + metadata); + FileLog.getInstance().tlStreamWriter.write("\n"); FileLog.getInstance().tlStreamWriter.write(req); FileLog.getInstance().tlStreamWriter.write("\n"); FileLog.getInstance().tlStreamWriter.write(finalRes); @@ -125,6 +126,7 @@ public class FileLog { String metadata = getInstance().dateFormat.format(time);// + " msgId=" + messageId; FileLog.getInstance().tlStreamWriter.write(metadata); + FileLog.getInstance().tlStreamWriter.write("\n"); FileLog.getInstance().tlStreamWriter.write(messageStr); FileLog.getInstance().tlStreamWriter.write("\n\n"); FileLog.getInstance().tlStreamWriter.flush(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index 02a45a0c2..d52dd1830 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -69,7 +69,9 @@ public class FileRefController extends BaseController { } public static String getKeyForParentObject(Object parentObject) { - if (parentObject instanceof TLRPC.TL_availableReaction) { + if (parentObject instanceof TLRPC.TL_help_premiumPromo) { + return "premium_promo"; + } else if (parentObject instanceof TLRPC.TL_availableReaction) { return "available_reaction_" + ((TLRPC.TL_availableReaction) parentObject).reaction; } else if (parentObject instanceof TLRPC.BotInfo) { TLRPC.BotInfo botInfo = (TLRPC.BotInfo) parentObject; @@ -317,7 +319,18 @@ public class FileRefController extends BaseController { } private void requestReferenceFromServer(Object parentObject, String locationKey, String parentKey, Object[] args) { - if (parentObject instanceof TLRPC.TL_availableReaction) { + if (parentObject instanceof TLRPC.TL_help_premiumPromo) { + TLRPC.TL_help_getPremiumPromo req = new TLRPC.TL_help_getPremiumPromo(); + getConnectionsManager().sendRequest(req, (response, error) -> { + int date = (int) (System.currentTimeMillis() / 1000); + if (response instanceof TLRPC.TL_help_premiumPromo) { + TLRPC.TL_help_premiumPromo r = (TLRPC.TL_help_premiumPromo) response; + getMediaDataController().processLoadedPremiumPromo(r, date, false); + } + + onRequestComplete(locationKey, parentKey, response, true, false); + }); + } else if (parentObject instanceof TLRPC.TL_availableReaction) { TLRPC.TL_messages_getAvailableReactions req = new TLRPC.TL_messages_getAvailableReactions(); req.hash = 0; getConnectionsManager().sendRequest(req, (response, error) -> onRequestComplete(locationKey, parentKey, response, true, false)); @@ -674,7 +687,9 @@ public class FileRefController extends BaseController { private boolean onRequestComplete(String locationKey, String parentKey, TLObject response, boolean cache, boolean fromCache) { boolean found = false; String cacheKey = parentKey; - if (response instanceof TLRPC.TL_account_wallPapers) { + if (response instanceof TLRPC.TL_help_premiumPromo) { + cacheKey = "premium_promo"; + } else if (response instanceof TLRPC.TL_account_wallPapers) { cacheKey = "wallpaper"; } else if (response instanceof TLRPC.TL_messages_savedGifs) { cacheKey = "gif"; @@ -754,6 +769,14 @@ public class FileRefController extends BaseController { } } } + } else if (response instanceof TLRPC.TL_help_premiumPromo) { + TLRPC.TL_help_premiumPromo premiumPromo = (TLRPC.TL_help_premiumPromo) response; + for (TLRPC.Document document : premiumPromo.videos) { + result = getFileReference(document, requester.location, needReplacement, locationReplacement); + if (result != null) { + break; + } + } } else if (response instanceof TLRPC.TL_messages_availableReactions) { TLRPC.TL_messages_availableReactions availableReactions = (TLRPC.TL_messages_availableReactions) response; getMediaDataController().processLoadedReactions(availableReactions.reactions, availableReactions.hash, (int) (System.currentTimeMillis() / 1000), false); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 78afcfeaa..619f54a8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -378,15 +378,18 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg if (userFull == null) { MessagesController.getInstance(currentAccount).loadFullUser(user, currentGuid, false); } else { - if (userFull.profile_photo != null && userFull.profile_photo.video_sizes != null && !userFull.profile_photo.video_sizes.isEmpty()) { - TLRPC.VideoSize videoSize = userFull.profile_photo.video_sizes.get(0); - for (int i = 0; i < userFull.profile_photo.video_sizes.size(); i++) { - if ("p".equals(userFull.profile_photo.video_sizes.get(i).type)) { - videoSize = userFull.profile_photo.video_sizes.get(i); - break; + if (userFull.profile_photo != null) { + TLRPC.Photo photo = userFull.profile_photo; + if (photo != null && photo.video_sizes != null && !photo.video_sizes.isEmpty()) { + TLRPC.VideoSize videoSize = photo.video_sizes.get(0); + for (int i = 0; i < photo.video_sizes.size(); i++) { + if ("p".equals(photo.video_sizes.get(i).type)) { + videoSize = photo.video_sizes.get(i); + break; + } } + videoLocation = ImageLocation.getForPhoto(videoSize, photo); } - videoLocation = ImageLocation.getForPhoto(videoSize, userFull.profile_photo); } } } @@ -1470,7 +1473,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg if (time == 0) { time = System.currentTimeMillis(); } - ((SvgHelper.SvgDrawable) drawable).drawInternal(canvas, true, time, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH); + ((SvgHelper.SvgDrawable) drawable).drawInternal(canvas, true, backgroundThreadDrawHolder.threadIndex, time, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH); } else { drawable.draw(canvas); } @@ -1487,9 +1490,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg private void drawBitmapDrawable(Canvas canvas, BitmapDrawable bitmapDrawable, BackgroundThreadDrawHolder backgroundThreadDrawHolder, int alpha) { if (backgroundThreadDrawHolder != null) { if (bitmapDrawable instanceof RLottieDrawable) { - ((RLottieDrawable) bitmapDrawable).drawInBackground(canvas, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH, alpha, backgroundThreadDrawHolder.colorFilter); + ((RLottieDrawable) bitmapDrawable).drawInBackground(canvas, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH, alpha, backgroundThreadDrawHolder.colorFilter, backgroundThreadDrawHolder.threadIndex); } else if (bitmapDrawable instanceof AnimatedFileDrawable) { - ((AnimatedFileDrawable) bitmapDrawable).drawInBackground(canvas, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH, alpha, backgroundThreadDrawHolder.colorFilter); + ((AnimatedFileDrawable) bitmapDrawable).drawInBackground(canvas, backgroundThreadDrawHolder.imageX, backgroundThreadDrawHolder.imageY, backgroundThreadDrawHolder.imageW, backgroundThreadDrawHolder.imageH, alpha, backgroundThreadDrawHolder.colorFilter, backgroundThreadDrawHolder.threadIndex); } else { Bitmap bitmap = bitmapDrawable.getBitmap(); if (bitmap != null) { @@ -1508,9 +1511,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } else { bitmapDrawable.setAlpha(alpha); if (bitmapDrawable instanceof RLottieDrawable) { - ((RLottieDrawable) bitmapDrawable).drawInternal(canvas, false, currentTime); + ((RLottieDrawable) bitmapDrawable).drawInternal(canvas, false, currentTime, 0); } else if (bitmapDrawable instanceof AnimatedFileDrawable) { - ((AnimatedFileDrawable) bitmapDrawable).drawInternal(canvas, false, currentTime); + ((AnimatedFileDrawable) bitmapDrawable).drawInternal(canvas, false, currentTime, 0); } else { bitmapDrawable.draw(canvas); } @@ -2895,10 +2898,11 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg return fileLoadingPriority; } - public BackgroundThreadDrawHolder setDrawInBackgroundThread(BackgroundThreadDrawHolder holder) { + public BackgroundThreadDrawHolder setDrawInBackgroundThread(BackgroundThreadDrawHolder holder, int threadIndex) { if (holder == null) { holder = new BackgroundThreadDrawHolder(); } + holder.threadIndex = threadIndex; holder.animation = getAnimation(); holder.lottieDrawable = getLottieAnimation(); for (int i = 0; i < 4; i++) { @@ -2931,6 +2935,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg public boolean animationNotReady; public float overrideAlpha; public long time; + public int threadIndex; private AnimatedFileDrawable animation; private RLottieDrawable lottieDrawable; private int[] roundRadius = new int[4]; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index e456770c2..c52af8d9a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -34,6 +34,7 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.URLSpan; import android.text.util.Linkify; +import android.util.Pair; import android.util.SparseArray; import androidx.annotation.NonNull; @@ -65,7 +66,6 @@ import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.ChatThemeBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.Reactions.ReactionsEffectOverlay; -import org.telegram.ui.Components.Reactions.ReactionsUtils; import org.telegram.ui.Components.StickerSetBulletinLayout; import org.telegram.ui.Components.StickersArchiveAlert; import org.telegram.ui.Components.TextStyleSpan; @@ -523,7 +523,7 @@ public class MediaDataController extends BaseController { } } - private void processLoadedPremiumPromo(TLRPC.TL_help_premiumPromo premiumPromo, int date, boolean cache) { + public void processLoadedPremiumPromo(TLRPC.TL_help_premiumPromo premiumPromo, int date, boolean cache) { this.premiumPromo = premiumPromo; premiumPromoUpdateDate = date; getMessagesController().putUsers(premiumPromo.users, cache); @@ -638,7 +638,7 @@ public class MediaDataController extends BaseController { reactionsUpdateDate = date; if (reactions != null) { AndroidUtilities.runOnUIThread(() -> { - preloadReactions(); + preloadDefaultReactions(); NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.reactionsDidLoad); }); } @@ -651,21 +651,23 @@ public class MediaDataController extends BaseController { } } - public void preloadReactions() { + public void preloadDefaultReactions() { if (reactionsList == null || reactionsCacheGenerated) { return; } reactionsCacheGenerated = true; ArrayList arrayList = new ArrayList<>(reactionsList); + for (int i = 0; i < arrayList.size(); i++) { + TLRPC.TL_availableReaction reaction = arrayList.get(i); + preloadImage(ImageLocation.getForDocument(reaction.activate_animation), null); + preloadImage(ImageLocation.getForDocument(reaction.appear_animation), null); + } + for (int i = 0; i < arrayList.size(); i++) { TLRPC.TL_availableReaction reaction = arrayList.get(i); int size = ReactionsEffectOverlay.sizeForBigReaction(); preloadImage(ImageLocation.getForDocument(reaction.around_animation), ReactionsEffectOverlay.getFilterForAroundAnimation(), true); - preloadImage(ImageLocation.getForDocument(reaction.effect_animation), size + "_" + size); - preloadImage(ImageLocation.getForDocument(reaction.activate_animation), null); - preloadImage(ImageLocation.getForDocument(reaction.appear_animation), ReactionsUtils.APPEAR_ANIMATION_FILTER); - - preloadImage(ImageLocation.getForDocument(reaction.center_icon), null); + preloadImage(ImageLocation.getForDocument(reaction.effect_animation), null); } } @@ -675,6 +677,9 @@ public class MediaDataController extends BaseController { private void preloadImage(ImageLocation location, String filter, boolean log) { ImageReceiver imageReceiver = new ImageReceiver(); + imageReceiver.setAllowStartAnimation(false); + imageReceiver.setAllowStartLottieAnimation(false); + imageReceiver.setAllowDecodeSingleFrame(false); imageReceiver.setDelegate((imageReceiver1, set, thumb, memCache) -> { if (set) { RLottieDrawable rLottieDrawable = imageReceiver.getLottieAnimation(); @@ -6061,6 +6066,19 @@ public class MediaDataController extends BaseController { return threads.get(threadId); } + public Pair getOneThreadDraft(long dialogId) { + SparseArray threads = drafts.get(dialogId); + if (threads == null || threads.size() <= 0) { + return null; + } + for (int i = 0; i < threads.size(); ++i) { + if (threads.keyAt(i) != 0) { + return new Pair(threads.keyAt(i), threads.valueAt(i)); + } + } + return null; + } + public TLRPC.Message getDraftMessage(long dialogId, int threadId) { SparseArray threads = draftMessages.get(dialogId); if (threads == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 48dc450cf..2cdae265c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -175,6 +175,8 @@ public class MessageObject { public boolean sponsoredShowPeerPhoto; public boolean sponsoredRecommended; + public TLRPC.TL_forumTopic replyToForumTopic; // used only for reply message in view all messages + public String botStartParam; public boolean animateComments; @@ -2547,7 +2549,7 @@ public class MessageObject { } public boolean hasValidReplyMessageObject() { - return !(replyMessageObject == null || replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionHistoryClear); + return !(replyMessageObject == null || replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionHistoryClear || replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate); } public void generatePaymentSentMessageText(TLRPC.User fromUser) { @@ -3442,10 +3444,13 @@ public class MessageObject { TLRPC.TL_messageActionTopicEdit editAction = (TLRPC.TL_messageActionTopicEdit) messageOwner.action; String name = null; + TLObject object = null; if (fromUser != null) { name = ContactsController.formatName(fromUser.first_name, fromUser.last_name); + object = fromUser; } else if (fromChat != null) { name = fromChat.title; + object = fromChat; } if (name != null) { name = name.trim(); @@ -3455,10 +3460,10 @@ public class MessageObject { if ((messageOwner.action.flags & 4) > 0) { if (((TLRPC.TL_messageActionTopicEdit) messageOwner.action).closed) { - messageText = LocaleController.formatString("TopicClosed2", R.string.TopicClosed2, name); + messageText = replaceWithLink(LocaleController.getString("TopicClosed2", R.string.TopicClosed2), "%s", object); messageTextShort = LocaleController.getString("TopicClosed", R.string.TopicClosed); } else { - messageText = LocaleController.formatString("TopicRestarted2", R.string.TopicRestarted2, name); + messageText = replaceWithLink(LocaleController.getString("TopicRestarted2", R.string.TopicRestarted2), "%s", object); messageTextShort = LocaleController.getString("TopicRestarted", R.string.TopicRestarted); } } else { @@ -4776,6 +4781,10 @@ public class MessageObject { } public static Spannable replaceAnimatedEmoji(CharSequence text, ArrayList entities, Paint.FontMetricsInt fontMetricsInt) { + return replaceAnimatedEmoji(text, entities, fontMetricsInt, false); + } + + public static Spannable replaceAnimatedEmoji(CharSequence text, ArrayList entities, Paint.FontMetricsInt fontMetricsInt, boolean top) { Spannable spannable = text instanceof Spannable ? (Spannable) text : new SpannableString(text); if (entities == null) { return spannable; @@ -4812,6 +4821,7 @@ public class MessageObject { } else { span = new AnimatedEmojiSpan(entity.document_id, fontMetricsInt); } + span.top = top; spannable.setSpan(span, messageEntity.offset, messageEntity.offset + messageEntity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } @@ -5524,6 +5534,22 @@ public class MessageObject { return false; } + public static boolean peersEqual(TLRPC.Chat a, TLRPC.Peer b) { + if (a == null && b == null) { + return true; + } + if (a == null || b == null) { + return false; + } + if (ChatObject.isChannel(a) && b instanceof TLRPC.TL_peerChannel) { + return a.id == b.channel_id; + } + if (!ChatObject.isChannel(a) && b instanceof TLRPC.TL_peerChat) { + return a.id == b.chat_id; + } + return false; + } + public long getFromChatId() { return getFromChatId(messageOwner); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 9e4fa8a02..3607e5585 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -85,6 +85,7 @@ public class MessagesController extends BaseController implements NotificationCe private ConcurrentHashMap encryptedChats = new ConcurrentHashMap<>(10, 1.0f, 2); private ConcurrentHashMap users = new ConcurrentHashMap<>(100, 1.0f, 2); private ConcurrentHashMap objectsByUsernames = new ConcurrentHashMap<>(100, 1.0f, 2); + public static int stableIdPointer = 100; private HashMap activeVoiceChatsMap = new HashMap<>(); @@ -365,6 +366,7 @@ public class MessagesController extends BaseController implements NotificationCe public int reactionsUserMaxPremium; public int reactionsInChatMax; public int forumUpgradeParticipantsMin; + public int topicsPinnedLimit; public int uploadMaxFileParts; public int uploadMaxFilePartsPremium; @@ -592,6 +594,13 @@ public class MessagesController extends BaseController implements NotificationCe getMessagesStorage().updateRepliesMaxReadId(-did, topic.id, topic.top_message, 0, true); } } + getMessagesStorage().getStorageQueue().postRunnable(() -> { + getMessagesStorage().resetAllUnreadCounters(false); + AndroidUtilities.runOnUIThread(() -> { + getMessagesController().sortDialogs(null); + getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload, true); + }); + }); }); }); } @@ -1103,6 +1112,7 @@ public class MessagesController extends BaseController implements NotificationCe premiumLocked = mainPreferences.getBoolean("premiumLocked", false); transcribeButtonPressed = mainPreferences.getInt("transcribeButtonPressed", 0); forumUpgradeParticipantsMin = mainPreferences.getInt("forumUpgradeParticipantsMin", 200); + topicsPinnedLimit = mainPreferences.getInt("topicsPinnedLimit", 3); BuildVars.GOOGLE_AUTH_CLIENT_ID = mainPreferences.getString("googleAuthClientId", BuildVars.GOOGLE_AUTH_CLIENT_ID); Set currencySet = mainPreferences.getStringSet("directPaymentsCurrency", null); @@ -2619,6 +2629,16 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "topics_pinned_limit": { + if (value.value instanceof TLRPC.TL_jsonNumber) { + TLRPC.TL_jsonNumber number = (TLRPC.TL_jsonNumber) value.value; + if (number.value != topicsPinnedLimit) { + topicsPinnedLimit = (int) number.value; + editor.putInt("topicsPinnedLimit", topicsPinnedLimit); + changed = true; + } + } + } } } if (changed) { @@ -3361,7 +3381,7 @@ public class MessagesController extends BaseController implements NotificationCe editor = emojiPreferences.edit(); editor.putLong("lastGifLoadTime", 0).putLong("lastStickersLoadTime", 0).putLong("lastStickersLoadTimeMask", 0).putLong("lastStickersLoadTimeFavs", 0).commit(); editor = mainPreferences.edit(); - editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").remove("showFiltersTooltip").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("reminderhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").remove("showFiltersTooltip").remove("transcribeButtonPressed").commit(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("shortcut_widget", Activity.MODE_PRIVATE); SharedPreferences.Editor widgetEditor = null; @@ -12546,6 +12566,8 @@ public class MessagesController extends BaseController implements NotificationCe return ((TLRPC.TL_updateReadChannelInbox) update).channel_id; } else if (update instanceof TLRPC.TL_updateChannelPinnedTopic) { return ((TLRPC.TL_updateChannelPinnedTopic) update).channel_id; + } else if (update instanceof TLRPC.TL_updateChannelPinnedTopics) { + return ((TLRPC.TL_updateChannelPinnedTopics) update).channel_id; } else if (update instanceof TLRPC.TL_updateReadChannelDiscussionInbox) { return ((TLRPC.TL_updateReadChannelDiscussionInbox) update).channel_id; } else if (update instanceof TLRPC.TL_updateReadChannelDiscussionOutbox) { @@ -13898,7 +13920,10 @@ public class MessagesController extends BaseController implements NotificationCe stillUnreadMessagesCount.put(dialogId, update.still_unread_count); dialogs_read_inbox_max.put(dialogId, Math.max(value, update.max_id)); FileLog.d("TL_updateReadChannelInbox " + dialogId + " new unread = " + update.still_unread_count + " max id = " + update.max_id + " from get diff " + fromGetDifference); - } else if (baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopic) { + } else if ( + baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopic || + baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopics + ) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); } @@ -14791,14 +14816,21 @@ public class MessagesController extends BaseController implements NotificationCe } else if (baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopic) { TLRPC.TL_updateChannelPinnedTopic update = (TLRPC.TL_updateChannelPinnedTopic) baseUpdate; - ArrayList topics = getTopicsController().getTopics(update.channel_id); - if (topics != null) { - for (int i = 0; i < topics.size(); ++i) { - topics.get(i).pinned = update.topic_id == topics.get(i).id; - } + ArrayList newOrder = getTopicsController().getCurrentPinnedOrder(update.channel_id); + newOrder.remove((Integer) update.topic_id); + if (update.pinned) { + newOrder.add(0, update.topic_id); } + getTopicsController().applyPinnedOrder(update.channel_id, newOrder); - updateMask |= UPDATE_MASK_SELECT_DIALOG; + } else if (baseUpdate instanceof TLRPC.TL_updateChannelPinnedTopics) { + TLRPC.TL_updateChannelPinnedTopics update = (TLRPC.TL_updateChannelPinnedTopics) baseUpdate; + + if ((update.flags & 1) > 0) { + getTopicsController().applyPinnedOrder(update.channel_id, update.order); + } else { + getTopicsController().reloadTopics(update.channel_id, false); + } } else if (baseUpdate instanceof TLRPC.TL_updatePhoneCallSignalingData) { TLRPC.TL_updatePhoneCallSignalingData data = (TLRPC.TL_updatePhoneCallSignalingData) baseUpdate; VoIPService svc = VoIPService.getSharedInstance(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 3e4837808..b75667f8b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -2383,10 +2383,14 @@ public class MessagesStorage extends BaseController { SQLitePreparedStatement state = null; try { HashSet existingTopics = new HashSet<>(); + HashMap pinnedValues = new HashMap<>(); for (int i = 0; i < topics.size(); i++) { TLRPC.TL_forumTopic topic = topics.get(i); - SQLiteCursor cursor = database.queryFinalized("SELECT did FROM topics WHERE did = " + dialogId + " AND topic_id = " + topic.id); + SQLiteCursor cursor = database.queryFinalized("SELECT did, pinned FROM topics WHERE did = " + dialogId + " AND topic_id = " + topic.id); boolean exist = cursor.next(); + if (exist) { + pinnedValues.put(i, cursor.intValue(2)); + } cursor.dispose(); cursor = null; if (exist) { @@ -2422,7 +2426,11 @@ public class MessagesStorage extends BaseController { state.bindInteger(8, topic.unread_mentions_count); state.bindInteger(9, topic.unread_reactions_count); state.bindInteger(10, topic.read_outbox_max_id); - state.bindInteger(11, topic.pinned ? 1 : 0); + if (topic.isShort && pinnedValues.containsKey(i)) { + state.bindInteger(11, pinnedValues.get(i)); + } else { + state.bindInteger(11, topic.pinned ? 1 + topic.pinnedOrder : 0); + } state.step(); messageData.reuse(); @@ -2487,8 +2495,9 @@ public class MessagesStorage extends BaseController { } if ((flags & TopicsController.TOPIC_FLAG_PIN) != 0) { topicToUpdate.pinned = fromTopic.pinned; + topicToUpdate.pinnedOrder = fromTopic.pinnedOrder; } - boolean pinned = topicToUpdate.pinned; + int pinnedOrder = topicToUpdate.pinned ? 1 + topicToUpdate.pinnedOrder : 0; if ((flags & TopicsController.TOPIC_FLAG_CLOSE) != 0) { topicToUpdate.closed = fromTopic.closed; } @@ -2497,7 +2506,7 @@ public class MessagesStorage extends BaseController { NativeByteBuffer data = new NativeByteBuffer(topicToUpdate.getObjectSize()); topicToUpdate.serializeToStream(data); state.bindByteBuffer(1, data); - state.bindInteger(2, pinned ? 1 : 0); + state.bindInteger(2, pinnedOrder); state.bindLong(3, dialogId); state.bindInteger(4, topicToUpdate.id); state.step(); @@ -2522,7 +2531,7 @@ public class MessagesStorage extends BaseController { ArrayList topics = null; SQLiteCursor cursor = null; try { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT top_message, data, topic_message, unread_count, max_read_id, unread_mentions, unread_reactions, read_outbox FROM topics WHERE did = %d ORDER BY pinned DESC", dialogId)); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT top_message, data, topic_message, unread_count, max_read_id, unread_mentions, unread_reactions, read_outbox, pinned FROM topics WHERE did = %d ORDER BY pinned ASC", dialogId)); SparseArray> topicsByTopMessageId = null; HashSet topMessageIds = null; @@ -2559,6 +2568,8 @@ public class MessagesStorage extends BaseController { topic.unread_mentions_count = cursor.intValue(5); topic.unread_reactions_count = cursor.intValue(6); topic.read_outbox_max_id = cursor.intValue(7); + topic.pinnedOrder = cursor.intValue(8) - 1; + topic.pinned = topic.pinnedOrder >= 0; } data.reuse(); @@ -10759,31 +10770,34 @@ public class MessagesStorage extends BaseController { SQLiteCursor cursor = null; try { long dialogId = -chatId; - state = database.executeFast("UPDATE messages_v2 SET replies_data = ? WHERE mid = ? AND uid = ?"); - TLRPC.MessageReplies currentReplies = null; - cursor = database.queryFinalized(String.format(Locale.US, "SELECT replies_data FROM messages_v2 WHERE mid = %d AND uid = %d", mid, dialogId)); - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - currentReplies = TLRPC.MessageReplies.TLdeserialize(data, data.readInt32(false), false); + if (!isForum(-chatId)) { + state = database.executeFast("UPDATE messages_v2 SET replies_data = ? WHERE mid = ? AND uid = ?"); + TLRPC.MessageReplies currentReplies = null; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT replies_data FROM messages_v2 WHERE mid = %d AND uid = %d", mid, dialogId)); + if (cursor.next()) { + NativeByteBuffer data = cursor.byteBufferValue(0); + if (data != null) { + currentReplies = TLRPC.MessageReplies.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); + } + } + cursor.dispose(); + + cursor = null; + if (currentReplies != null) { + currentReplies.read_max_id = readMaxId; + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(currentReplies.getObjectSize()); + currentReplies.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindInteger(2, mid); + state.bindLong(3, dialogId); + state.step(); data.reuse(); } + state.dispose(); + state = null; } - cursor.dispose(); - cursor = null; - if (currentReplies != null) { - currentReplies.read_max_id = readMaxId; - state.requery(); - NativeByteBuffer data = new NativeByteBuffer(currentReplies.getObjectSize()); - currentReplies.serializeToStream(data); - state.bindByteBuffer(1, data); - state.bindInteger(2, mid); - state.bindLong(3, dialogId); - state.step(); - data.reuse(); - } - state.dispose(); - state = null; cursor = database.queryFinalized(String.format(Locale.US, "SELECT max_read_id FROM topics WHERE did = %d AND topic_id = %d", -chatId, mid)); @@ -11908,7 +11922,7 @@ public class MessagesStorage extends BaseController { topicUpdate.topicId = topicKey.topicId; topicUpdate.reloadTopic = true; topicUpdatesInUi.add(topicUpdate); - FileLog.d("unknown topic need reload" + topicKey.dialogId + " " + topicKey.topicId); + FileLog.d("unknown topic need reload " + topicKey.dialogId + " " + topicKey.topicId); continue; } Integer newMessagesInteger = topicsNewUnreadMessages.get(topicKey); @@ -12097,7 +12111,6 @@ public class MessagesStorage extends BaseController { private void createOrEditTopic(long dialogId, TLRPC.Message message) { TLRPC.TL_forumTopic forumTopic = new TLRPC.TL_forumTopic(); - forumTopic.topicStartMessage = message; forumTopic.top_message = message.id; forumTopic.topMessage = message; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index 18f4910e8..2cb0024c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -130,6 +130,7 @@ public class NotificationCenter { public static final int voiceTranscriptionUpdate = totalEvents++; public static final int animatedEmojiDocumentLoaded = totalEvents++; public static final int recentEmojiStatusesUpdate = totalEvents++; + public static final int updateSearchSettings = totalEvents++; public static final int didGenerateFingerprintKeyPair = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java index 292cb4861..9398ccaff 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SharedConfig.java @@ -356,7 +356,7 @@ public class SharedConfig { if (updateVersionString == null) { updateVersionString = BuildVars.BUILD_VERSION_STRING; } - if (pendingAppUpdateBuildVersion != updateVersion || pendingAppUpdate.version == null || updateVersionString.compareTo(pendingAppUpdate.version) >= 0) { + if (pendingAppUpdateBuildVersion != updateVersion || pendingAppUpdate.version == null || updateVersionString.compareTo(pendingAppUpdate.version) >= 0 || BuildVars.DEBUG_PRIVATE_VERSION) { pendingAppUpdate = null; AndroidUtilities.runOnUIThread(SharedConfig::saveConfig); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java index e0c8470bc..26762b8f0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SvgHelper.java @@ -42,6 +42,7 @@ import android.os.Build; import android.util.SparseArray; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.DrawingInBackgroundThreadDrawable; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; @@ -108,10 +109,10 @@ public class SvgHelper { protected int height; private static int[] parentPosition = new int[2]; - private Bitmap[] backgroundBitmap = new Bitmap[2]; - private Canvas[] backgroundCanvas = new Canvas[2]; - private LinearGradient[] placeholderGradient = new LinearGradient[2]; - private Matrix[] placeholderMatrix = new Matrix[2]; + private Bitmap[] backgroundBitmap = new Bitmap[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Canvas[] backgroundCanvas = new Canvas[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private LinearGradient[] placeholderGradient = new LinearGradient[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Matrix[] placeholderMatrix = new Matrix[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; private static float totalTranslation; private static float gradientWidth; private static long lastUpdateTime; @@ -154,10 +155,10 @@ public class SvgHelper { @Override public void draw(Canvas canvas) { - drawInternal(canvas, false, System.currentTimeMillis(), getBounds().left, getBounds().top, getBounds().width(), getBounds().height()); + drawInternal(canvas, false, 0, System.currentTimeMillis(), getBounds().left, getBounds().top, getBounds().width(), getBounds().height()); } - public void drawInternal(Canvas canvas, boolean drawInBackground, long time, float x, float y, float w, float h) { + public void drawInternal(Canvas canvas, boolean drawInBackground, int threadIndex, long time, float x, float y, float w, float h) { if (currentColorKey != null) { setupGradient(currentColorKey, currentResourcesProvider, colorAlpha, drawInBackground); } @@ -205,7 +206,7 @@ public class SvgHelper { offset = 0; } - int index = drawInBackground ? 1 : 0; + int index = drawInBackground ? 1 + threadIndex : 0; if (placeholderMatrix[index] != null) { placeholderMatrix[index].reset(); if (drawInBackground) { @@ -365,6 +366,11 @@ public class SvgHelper { currentColorKey = colorKey; } + public void setColorKey(String colorKey, Theme.ResourcesProvider resourcesProvider) { + currentColorKey = colorKey; + currentResourcesProvider = resourcesProvider; + } + public void setColor(int color) { overrideColor = color; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java index bf4683af9..ae4ac210d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TopicsController.java @@ -14,6 +14,8 @@ import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.Forum.ForumUtilities; import java.util.ArrayList; @@ -56,12 +58,11 @@ public class TopicsController extends BaseController { loadTopics(chatId, true, LOAD_TYPE_PRELOAD); } - public void loadTopics(long chatId) { loadTopics(chatId, false, LOAD_TYPE_LOAD_NEXT); } - private void loadTopics(long chatId, boolean fromCache, int loadType) { + public void loadTopics(long chatId, boolean fromCache, int loadType) { if (topicsIsLoading.get(chatId, 0) != 0) { return; } @@ -78,6 +79,10 @@ public class TopicsController extends BaseController { topicsIsLoading.put(chatId, 0); processTopics(chatId, topics, null, fromCache, loadType, -1); + + if (!endIsReached(chatId)) { + endIsReached.put(chatId, getUserConfig().getPreferences().getBoolean("topics_end_reached_" + chatId, false) ? 1 : 0); + } }); }); return; @@ -120,7 +125,7 @@ public class TopicsController extends BaseController { if (!topics.topics.isEmpty() && loadType == LOAD_TYPE_LOAD_NEXT) { TLRPC.TL_forumTopic lastTopic = topics.topics.get(topics.topics.size() - 1); TLRPC.Message lastTopicMessage = messagesMap.get(lastTopic.top_message); - saveLoadOffset(chatId, lastTopic.top_message, lastTopicMessage.date, lastTopic.id); + saveLoadOffset(chatId, lastTopic.top_message, lastTopicMessage == null ? 0 : lastTopicMessage.date, lastTopic.id); } else if (getTopics(chatId) == null || getTopics(chatId).size() < topics.count) { clearLoadingOffset(chatId); loadTopics(chatId); @@ -144,22 +149,25 @@ public class TopicsController extends BaseController { if (topics == null) { topics = new ArrayList<>(); topicsByChatId.put(chatId, topics); - } if (topicsMap == null) { topicsMap = new LongSparseArray<>(); topicsMapByChatId.put(chatId, topicsMap); } + boolean changed = false; if (newTopics != null) { for (int i = 0; i < newTopics.size(); i++) { TLRPC.TL_forumTopic newTopic = newTopics.get(i); + if (newTopic instanceof TLRPC.TL_forumTopicDeleted) { + continue; + } if (!topicsMap.containsKey(newTopic.id)) { if (messagesMap != null) { newTopic.topMessage = messagesMap.get(newTopic.top_message); newTopic.topicStartMessage = messagesMap.get(newTopic.id); } - if (newTopic.topMessage == null) { + if (newTopic.topMessage == null && !newTopic.isShort) { if (topicsToReload == null) { topicsToReload = new ArrayList<>(); } @@ -182,20 +190,35 @@ public class TopicsController extends BaseController { } } + int pinnedTopics = 0; + for (int i = 0; i < topics.size(); ++i) { + TLRPC.TL_forumTopic topic = topics.get(i); + if (topic != null && topic.pinned) { + int newPinnedOrder = pinnedTopics++; + if (topic.pinnedOrder != newPinnedOrder) { + topic.pinnedOrder = newPinnedOrder; + changed = true; + } + } + } + if (changed) { sortTopics(chatId); } - if (topicsToReload != null) { + if (topicsToReload != null && loadType != LOAD_TYPE_LOAD_UNKNOWN) { reloadTopics(chatId, topicsToReload); } else if (loadType == LOAD_TYPE_LOAD_NEXT && topics.size() >= totalCount && totalCount >= 0) { endIsReached.put(chatId, 1); + getUserConfig().getPreferences().edit().putBoolean("topics_end_reached_" + chatId, true).apply(); } getNotificationCenter().postNotificationName(NotificationCenter.topicsDidLoaded, chatId, true); if ((loadType == LOAD_TYPE_PRELOAD || (loadType == LOAD_TYPE_PRELOAD && !fromCache)) && fromCache && topicsByChatId.get(chatId).isEmpty()) { - loadTopics(chatId, false, LOAD_TYPE_PRELOAD); + AndroidUtilities.runOnUIThread(() -> { + loadTopics(chatId, false, LOAD_TYPE_PRELOAD); + }); } } @@ -212,11 +235,11 @@ public class TopicsController extends BaseController { sortTopics(chatId, true); } - private void sortTopics(long chatId, boolean notify) { + public void sortTopics(long chatId, boolean notify) { ArrayList topics = topicsByChatId.get(chatId); if (topics != null) { if (openedTopicsBuChatId.get(chatId, 0) > 0) { - Collections.sort(topics, Comparator.comparingInt(o -> o.pinned ? -1 : -o.topMessage.date)); + Collections.sort(topics, Comparator.comparingInt(o -> o.topMessage == null ? Integer.MAX_VALUE : -(o.pinned ? Integer.MAX_VALUE - o.pinnedOrder : o.topMessage.date))); } if (notify) { getNotificationCenter().postNotificationName(NotificationCenter.topicsDidLoaded, chatId, true); @@ -510,33 +533,106 @@ public class TopicsController extends BaseController { }); } - public void pinTopic(long chatId, int topicId, boolean pin) { + public ArrayList getCurrentPinnedOrder(long chatId) { + ArrayList topics = getTopics(chatId); + ArrayList newOrder = new ArrayList<>(); + if (topics != null) { + for (int i = 0; i < topics.size(); ++i) { + TLRPC.TL_forumTopic topic = topics.get(i); + if (topic == null) { + continue; + } + if (topic.pinned) { + newOrder.add(topic.id); + } + } + } + return newOrder; + } + + public void applyPinnedOrder(long chatId, ArrayList order) { + applyPinnedOrder(chatId, order, true); + } + + public void applyPinnedOrder(long chatId, ArrayList order, boolean notify) { + if (order == null) { + return; + } + + ArrayList topics = getTopics(chatId); + boolean updated = false; + if (topics != null) { + for (int i = 0; i < topics.size(); ++i) { + TLRPC.TL_forumTopic topic = topics.get(i); + if (topic == null) { + continue; + } + int newPinnedOrder = order.indexOf(topic.id); + boolean newPinned = newPinnedOrder >= 0; + if (topic.pinned != newPinned || newPinned && topic.pinnedOrder != newPinnedOrder) { + updated = true; + topic.pinned = newPinned; + topic.pinnedOrder = newPinnedOrder; + getMessagesStorage().updateTopicData(chatId, topic, TopicsController.TOPIC_FLAG_PIN); + } + } + } else { + updated = true; + } + + if (notify && updated) { + AndroidUtilities.runOnUIThread(() -> { + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_SELECT_DIALOG); + }); + } + } + + public void pinTopic(long chatId, int topicId, boolean pin, BaseFragment fragment) { TLRPC.TL_channels_updatePinnedForumTopic req = new TLRPC.TL_channels_updatePinnedForumTopic(); req.channel = getMessagesController().getInputChannel(chatId); req.topic_id = topicId; req.pinned = pin; - ArrayList topics = topicsByChatId.get(chatId); - if (topics != null) { - for (int i = 0; i < topics.size(); ++i) { - TLRPC.TL_forumTopic topic = topics.get(i); - if (topic != null && (topicId == topic.id && pin) != topic.pinned) { - topic.pinned = topicId == topic.id && pin; -// topic.flags = topic.pinned ? (topic.flags | 8) : (topic.flags &~ 8); - getMessagesStorage().updateTopicData(-chatId, topic, TOPIC_FLAG_PIN); - } - } + ArrayList prevOrder = getCurrentPinnedOrder(chatId); + ArrayList newOrder = new ArrayList<>(prevOrder); + newOrder.remove((Integer) topicId); + if (pin) { + newOrder.add(0, topicId); } - - sortTopics(chatId); + applyPinnedOrder(chatId, newOrder); ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { - if (response instanceof TLRPC.Updates) { -// getMessagesController().processUpdates((TLRPC.Updates) response, false); + if (error != null) { + if ("PINNED_TOO_MUCH".equals(error.text)) { + if (fragment == null) { + return; + } + applyPinnedOrder(chatId, prevOrder); + fragment.showDialog( + new AlertDialog.Builder(fragment.getContext()) + .setTitle(LocaleController.getString("LimitReached", R.string.LimitReached)) + .setMessage(LocaleController.formatString("LimitReachedPinnedTopics", R.string.LimitReachedPinnedTopics, MessagesController.getInstance(currentAccount).topicsPinnedLimit)) + .setPositiveButton(LocaleController.getString("OK", R.string.OK), null) + .create() + ); + } else if ("PINNED_TOPIC_NOT_MODIFIED".equals(error.text)) { + reloadTopics(chatId, false); + } } }); } + public void reorderPinnedTopics(long chatId, ArrayList topics) { + TLRPC.TL_channels_reorderPinnedForumTopics req = new TLRPC.TL_channels_reorderPinnedForumTopics(); + req.channel = getMessagesController().getInputChannel(chatId); + if (topics != null) { + req.order.addAll(topics); + } + req.force = true; + applyPinnedOrder(chatId, topics, false); + ConnectionsManager.getInstance(currentAccount).sendRequest(req, null); + } + public void updateMentionsUnread(long dialogId, int topicId, int topicMentionsCount) { AndroidUtilities.runOnUIThread(() -> { TLRPC.TL_forumTopic topic = findTopic(-dialogId, topicId); @@ -713,7 +809,12 @@ public class TopicsController extends BaseController { } public void reloadTopics(long chatId) { + reloadTopics(chatId, true); + } + + public void reloadTopics(long chatId, boolean fromCache) { AndroidUtilities.runOnUIThread(() -> { + getUserConfig().getPreferences().edit().remove("topics_end_reached_" + chatId).apply(); topicsByChatId.remove(chatId); topicsMapByChatId.remove(chatId); endIsReached.delete(chatId); @@ -722,7 +823,11 @@ public class TopicsController extends BaseController { TLRPC.Chat chat = getMessagesController().getChat(chatId); if (chat != null && chat.forum) { - preloadTopics(chatId); + if (fromCache) { + preloadTopics(chatId); + } else { + loadTopics(chatId, false, LOAD_TYPE_PRELOAD); + } } sortTopics(chatId); }); @@ -745,13 +850,15 @@ public class TopicsController extends BaseController { if (key.startsWith("topics_load_offset_topic_id_")) { editor.remove(key); } + if (key.startsWith("topics_end_reached_")) { + editor.remove(key); + } } editor.apply(); }); } public void updateReadOutbox(HashMap topicsReadOutbox) { - AndroidUtilities.runOnUIThread(() -> { HashSet updatedChats = new HashSet<>(); for (MessagesStorage.TopicKey topicKey : topicsReadOutbox.keySet()) { @@ -760,7 +867,7 @@ public class TopicsController extends BaseController { if (topic != null) { topic.read_outbox_max_id = Math.max(topic.read_outbox_max_id, value); updatedChats.add(-topicKey.dialogId); - if ( topic.read_outbox_max_id >= topic.topMessage.id) { + if (topic.read_outbox_max_id >= topic.topMessage.id) { topic.topMessage.unread = false; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java index 7673d4a02..1ae05ed4b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/utils/BitmapsCache.java @@ -6,19 +6,23 @@ import android.os.Build; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.DispatchQueuePoolBackground; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.Utilities; +import org.telegram.ui.Components.RLottieDrawable; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -37,18 +41,40 @@ public class BitmapsCache { ArrayList frameOffsets = new ArrayList<>(); + + final boolean useSharedBuffers; + static ConcurrentHashMap sharedBuffers = new ConcurrentHashMap(); + static volatile boolean cleanupScheduled; byte[] bufferTmp; - private final static int N = Utilities.clamp(Runtime.getRuntime().availableProcessors() - 2, 8, 1); + private final static int N = Utilities.clamp(Runtime.getRuntime().availableProcessors(), 8, 1); private static ThreadPoolExecutor bitmapCompressExecutor; private final Object mutex = new Object(); private int frameIndex; boolean error; + boolean fileExist; int compressQuality; final File file; + private int tryCount; + public AtomicBoolean cancelled = new AtomicBoolean(false); + private Runnable cleanupSharedBuffers = new Runnable() { + @Override + public void run() { + for (Thread thread : sharedBuffers.keySet()) { + if (!thread.isAlive()) { + sharedBuffers.remove(thread); + } + } + if (!sharedBuffers.isEmpty()) { + AndroidUtilities.runOnUIThread(cleanupSharedBuffers, 5000); + } else { + cleanupScheduled = false; + } + } + }; public BitmapsCache(File sourceFile, Cacheable source, CacheOptions options, int w, int h, boolean noLimit) { this.source = source; @@ -62,6 +88,38 @@ public class BitmapsCache { File fileTmo = new File(FileLoader.checkDirectory(FileLoader.MEDIA_DIR_CACHE), "acache"); file = new File(fileTmo, fileName + "_" + w + "_" + h + (noLimit ? "_nolimit" : " ") + ".pcache2"); + useSharedBuffers = w < AndroidUtilities.dp(60) && h < AndroidUtilities.dp(60); + fileExist = file.exists(); + if (fileExist) { + RandomAccessFile randomAccessFile = null; + try { + randomAccessFile = new RandomAccessFile(file, "r"); + cacheCreated = randomAccessFile.readBoolean(); + if (cacheCreated && frameOffsets.isEmpty()) { + randomAccessFile.seek(randomAccessFile.readInt()); + int count = randomAccessFile.readInt(); + fillFrames(randomAccessFile, count); + if (count == 0) { + file.delete(); + cacheCreated = false; + fileExist = false; + } + } + + } catch (Throwable e) { + e.printStackTrace(); + file.delete(); + fileExist = false; + } finally { + try { + if (randomAccessFile != null) { + randomAccessFile.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } } volatile boolean checkCache; @@ -71,6 +129,27 @@ public class BitmapsCache { RandomAccessFile cachedFile; BitmapFactory.Options options; + private static int taskCounter; + private static CacheGeneratorSharedTools sharedTools; + + public static void incrementTaskCounter() { + taskCounter++; + } + + public static void decrementTaskCounter() { + taskCounter--; + if (taskCounter <= 0) { + taskCounter = 0; + RLottieDrawable.lottieCacheGenerateQueue.postRunnable(() -> { + if (sharedTools != null) { + sharedTools.release(); + sharedTools = null; + } + }); + } + + } + public void createCache() { try { long time = System.currentTimeMillis(); @@ -84,7 +163,12 @@ public class BitmapsCache { cacheCreated = false; } if (cacheCreated) { + frameOffsets.clear(); + randomAccessFile.seek(randomAccessFile.readInt()); + int count = randomAccessFile.readInt(); + fillFrames(randomAccessFile, count); randomAccessFile.close(); + fileExist = true; return; } else { file.delete(); @@ -108,18 +192,17 @@ public class BitmapsCache { RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); - - Bitmap[] bitmap = new Bitmap[N]; - ByteArrayOutputStream[] byteArrayOutputStream = new ByteArrayOutputStream[N]; - CountDownLatch[] countDownLatch = new CountDownLatch[N]; - for (int i = 0; i < N; i++) { - bitmap[i] = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - byteArrayOutputStream[i] = new ByteArrayOutputStream(w * h * 2); + if (sharedTools == null) { + sharedTools = new CacheGeneratorSharedTools(); } + sharedTools.allocate(h, w); + Bitmap[] bitmap = sharedTools.bitmap; + ByteArrayOutputStream[] byteArrayOutputStream = sharedTools.byteArrayOutputStream; + CountDownLatch[] countDownLatch = new CountDownLatch[N]; + ArrayList frameOffsets = new ArrayList<>(); RandomAccessFile finalRandomAccessFile = randomAccessFile; - finalRandomAccessFile.writeBoolean(false); finalRandomAccessFile.writeInt(0); @@ -131,6 +214,7 @@ public class BitmapsCache { AtomicBoolean closed = new AtomicBoolean(false); source.prepareForGenerateCache(); + while (true) { if (countDownLatch[index] != null) { try { @@ -204,7 +288,8 @@ public class BitmapsCache { e.printStackTrace(); try { finalRandomAccessFile1.close(); - } catch (Exception e2) {} finally { + } catch (Exception e2) { + } finally { closed.set(true); } } @@ -226,35 +311,33 @@ public class BitmapsCache { e.printStackTrace(); } } - if (bitmap[i] != null) { - try { - bitmap[i].recycle(); - } catch (Exception e) { - - } - } - if (byteArrayOutputStream[i] != null) { - byteArrayOutputStream[i].buf = null; - } } int arrayOffset = (int) randomAccessFile.length(); Collections.sort(frameOffsets, Comparator.comparingInt(o -> o.index)); - randomAccessFile.writeInt(frameOffsets.size()); + byteArrayOutputStream[0].reset(); + int count = frameOffsets.size(); + byteArrayOutputStream[0].writeInt(count); for (int i = 0; i < frameOffsets.size(); i++) { - randomAccessFile.writeInt(frameOffsets.get(i).frameOffset); - randomAccessFile.writeInt(frameOffsets.get(i).frameSize); + byteArrayOutputStream[0].writeInt(frameOffsets.get(i).frameOffset); + byteArrayOutputStream[0].writeInt(frameOffsets.get(i).frameSize); } + randomAccessFile.write(byteArrayOutputStream[0].buf, 0, 4 + 4 * 2 * count); + byteArrayOutputStream[0].reset(); randomAccessFile.seek(0); randomAccessFile.writeBoolean(true); randomAccessFile.writeInt(arrayOffset); closed.set(true); randomAccessFile.close(); - if (BuildVars.DEBUG_VERSION) { - FileLog.d("generate cache for time = " + (System.currentTimeMillis() - time) + " drawFrameTime = " + bitmapFrameTime + " comressQuality = " + compressQuality + " fileSize = " + AndroidUtilities.formatFileSize(file.length()) + " " + fileName); - } + this.frameOffsets.clear(); +// this.frameOffsets.addAll(frameOffsets); + fileExist = true; + +// if (BuildVars.DEBUG_VERSION) { +// FileLog.d("generate cache for time = " + (System.currentTimeMillis() - time) + " drawFrameTime = " + bitmapFrameTime + " comressQuality = " + compressQuality + " fileSize = " + AndroidUtilities.formatFileSize(file.length()) + " " + fileName); +// } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { @@ -264,6 +347,18 @@ public class BitmapsCache { } } + private void fillFrames(RandomAccessFile randomAccessFile, int count) throws Throwable { + byte[] bytes = new byte[4 * 2 * count]; + randomAccessFile.read(bytes); + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + for (int i = 0; i < count; i++) { + FrameOffset frameOffset = new FrameOffset(i); + frameOffset.frameOffset = byteBuffer.getInt(); + frameOffset.frameSize = byteBuffer.getInt(); + frameOffsets.add(frameOffset); + } + } + public void cancelCreate() { // cancelled.set(true); } @@ -317,49 +412,43 @@ public class BitmapsCache { RandomAccessFile randomAccessFile = null; try { FrameOffset selectedFrame; - synchronized (mutex) { - if (!cacheCreated || cachedFile == null) { - randomAccessFile = new RandomAccessFile(file, "r"); - cacheCreated = randomAccessFile.readBoolean(); - if (cacheCreated && frameOffsets.isEmpty()) { - randomAccessFile.seek(randomAccessFile.readInt()); - int count = randomAccessFile.readInt(); - - for (int i = 0; i < count; i++) { - FrameOffset frameOffset = new FrameOffset(i); - frameOffset.frameOffset = randomAccessFile.readInt(); - frameOffset.frameSize = randomAccessFile.readInt(); - frameOffsets.add(frameOffset); - } - } - - if (!cacheCreated) { - randomAccessFile.close(); - randomAccessFile = null; - source.getFirstFrame(bitmap); - return FRAME_RESULT_OK; - } else if (frameOffsets.isEmpty()) { - randomAccessFile.close(); - randomAccessFile = null; - return FRAME_RESULT_NO_FRAME; - } - } else { - randomAccessFile = cachedFile; - } - index = Utilities.clamp(index, frameOffsets.size() - 1, 0); - selectedFrame = frameOffsets.get(index); - randomAccessFile.seek(selectedFrame.frameOffset); - if (bufferTmp == null || bufferTmp.length < selectedFrame.frameSize) { - bufferTmp = new byte[(int) (selectedFrame.frameSize * 1.3f)]; - } - randomAccessFile.readFully(bufferTmp, 0, selectedFrame.frameSize); - if (!recycled) { - cachedFile = randomAccessFile; - } else { - cachedFile = null; - randomAccessFile.close(); - } + if (!cacheCreated && !fileExist) { + return FRAME_RESULT_NO_FRAME; } + byte[] bufferTmp; + if (!cacheCreated || cachedFile == null) { + randomAccessFile = new RandomAccessFile(file, "r"); + cacheCreated = randomAccessFile.readBoolean(); + if (cacheCreated && frameOffsets.isEmpty()) { + randomAccessFile.seek(randomAccessFile.readInt()); + int count = randomAccessFile.readInt(); + fillFrames(randomAccessFile, count); + } + if (frameOffsets.size() == 0) { + cacheCreated = false; + } + + if (!cacheCreated) { + randomAccessFile.close(); + randomAccessFile = null; + return FRAME_RESULT_NO_FRAME; + } + } else { + randomAccessFile = cachedFile; + } + index = Utilities.clamp(index, frameOffsets.size() - 1, 0); + selectedFrame = frameOffsets.get(index); + randomAccessFile.seek(selectedFrame.frameOffset); + + bufferTmp = getBuffer(selectedFrame); + randomAccessFile.readFully(bufferTmp, 0, selectedFrame.frameSize); + if (!recycled) { + cachedFile = randomAccessFile; + } else { + cachedFile = null; + randomAccessFile.close(); + } + if (options == null) { options = new BitmapFactory.Options(); } @@ -370,9 +459,13 @@ public class BitmapsCache { } catch (Throwable e) { FileLog.e(e, false); + tryCount++; + if (tryCount > 10) { + error = true; + } } - if (randomAccessFile != null) { + if (error && randomAccessFile != null) { try { randomAccessFile.close(); } catch (IOException e) { @@ -380,12 +473,36 @@ public class BitmapsCache { } } - // source.getFirstFrame(bitmap); + // source.getFirstFrame(bitmap); return FRAME_RESULT_NO_FRAME; } + private byte[] getBuffer(FrameOffset selectedFrame) { + boolean useSharedBuffers = this.useSharedBuffers && Thread.currentThread().getName().startsWith(DispatchQueuePoolBackground.THREAD_PREFIX); + byte[] bufferTmp; + if (useSharedBuffers) { + bufferTmp = sharedBuffers.get(Thread.currentThread()); + } else { + bufferTmp = this.bufferTmp; + } + + if (bufferTmp == null || bufferTmp.length < selectedFrame.frameSize) { + bufferTmp = new byte[(int) (selectedFrame.frameSize * 1.3f)]; + if (useSharedBuffers) { + sharedBuffers.put(Thread.currentThread(), bufferTmp); + if (!cleanupScheduled) { + cleanupScheduled = true; + AndroidUtilities.runOnUIThread(cleanupSharedBuffers, 5000); + } + } else { + this.bufferTmp = bufferTmp; + } + } + return bufferTmp; + } + public boolean needGenCache() { - return !cacheCreated; + return !cacheCreated || !fileExist; } public void recycle() { @@ -416,7 +533,9 @@ public class BitmapsCache { public interface Cacheable { void prepareForGenerateCache(); + int getNextFrame(Bitmap bitmap); + void releaseForGenerateCache(); Bitmap getFirstFrame(Bitmap bitmap); @@ -437,8 +556,9 @@ public class BitmapsCache { } private void ensureCapacity(int minCapacity) { - if (minCapacity - buf.length > 0) + if (minCapacity - buf.length > 0) { grow(minCapacity); + } } private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; @@ -467,6 +587,15 @@ public class BitmapsCache { count += 1; } + public void writeInt(int value) { + ensureCapacity(count + 4); + buf[count] = (byte) (value >>> 24); + buf[count + 1] = (byte) (value >>> 16); + buf[count + 2] = (byte) (value >>> 8); + buf[count + 3] = (byte) (value); + count += 4; + } + public synchronized void write(byte b[], int off, int len) { if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) - b.length > 0)) { @@ -484,6 +613,8 @@ public class BitmapsCache { public synchronized void reset() { count = 0; } + + } public static class Metadata { @@ -494,4 +625,61 @@ public class BitmapsCache { public int compressQuality = 100; public boolean fallback = false; } + + private static class CacheGeneratorSharedTools { + ByteArrayOutputStream[] byteArrayOutputStream = new ByteArrayOutputStream[N]; + private Bitmap[] bitmap = new Bitmap[N]; + + private int lastSize; + + void allocate(int h, int w) { + int size = (w << 16) + h; + boolean recreateBitmaps = false; + if (lastSize != size) { + recreateBitmaps = true; + } + lastSize = size; + for (int i = 0; i < N; i++) { + if (recreateBitmaps || bitmap[i] == null) { + if (bitmap[i] != null) { + Bitmap bitmapToRecycle = bitmap[i]; + Utilities.globalQueue.postRunnable(() -> { + try { + bitmapToRecycle.recycle(); + } catch (Exception e) { + + } + }); + } + bitmap[i] = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + } + if (byteArrayOutputStream[i] == null) { + byteArrayOutputStream[i] = new ByteArrayOutputStream(w * h * 2); + } + } + } + + void release() { + ArrayList bitmapsToRecycle = null; + for (int i = 0; i < N; i++) { + if (bitmap[i] != null) { + if (bitmapsToRecycle == null) { + bitmapsToRecycle = new ArrayList<>(); + } + bitmapsToRecycle.add(bitmap[i]); + } + bitmap[i] = null; + byteArrayOutputStream[i] = null; + } + if (!bitmapsToRecycle.isEmpty()) { + ArrayList finalBitmapsToRecycle = bitmapsToRecycle; + Utilities.globalQueue.postRunnable(() -> { + for (Bitmap bitmap : finalBitmapsToRecycle) { + bitmap.recycle(); + } + }); + } + } + + } } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index da32dfc87..1942a2ce3 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -18,6 +18,7 @@ import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.Utilities; @@ -68,11 +69,10 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_EDITED = 0x00008000; - public static final int LAYER = 148; + public static final int LAYER = 149; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; - public TL_statsDateRangeDays period; public TL_statsAbsValueAndPrev members; public TL_statsAbsValueAndPrev messages; @@ -3112,6 +3112,7 @@ public class TLRPC { public ArrayList messages = new ArrayList<>(); public ArrayList chats = new ArrayList<>(); public ArrayList users = new ArrayList<>(); + public ArrayList topics = new ArrayList<>(); public int flags; public boolean inexact; public int pts; @@ -3129,7 +3130,7 @@ public class TLRPC { case 0x8c718e87: result = new TL_messages_messages(); break; - case 0x64479808: + case 0xc776ba4e: result = new TL_messages_channelMessages(); break; case 0x74535f21: @@ -3315,8 +3316,7 @@ public class TLRPC { } public static class TL_messages_channelMessages extends messages_Messages { - public static int constructor = 0x64479808; - + public static int constructor = 0xc776ba4e; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -3349,6 +3349,21 @@ public class TLRPC { return; } count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_forumTopic object = TL_forumTopic.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + topics.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); for (int a = 0; a < count; a++) { Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); if (object == null) { @@ -3389,6 +3404,12 @@ public class TLRPC { messages.get(a).serializeToStream(stream); } stream.writeInt32(0x1cb5c415); + count = topics.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + topics.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); count = chats.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { @@ -30931,7 +30952,10 @@ public class TLRPC { case 0x14b85813: result = new TL_updateBotMenuButton(); break; - case 0xf694b0ae: + case 0xfe198602: + result = new TL_updateChannelPinnedTopics(); + break; + case 0x192efbe3: result = new TL_updateChannelPinnedTopic(); break; } @@ -33144,18 +33168,28 @@ public class TLRPC { } } - public static class TL_updateChannelPinnedTopic extends Update { - public static int constructor = 0xf694b0ae; + public static class TL_updateChannelPinnedTopics extends Update { + public static int constructor = 0xfe198602; public int flags; public long channel_id; - public int topic_id; + public ArrayList order = new ArrayList<>(); public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); channel_id = stream.readInt64(exception); if ((flags & 1) != 0) { - topic_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + order.add(stream.readInt32(exception)); + } } } @@ -33164,11 +33198,40 @@ public class TLRPC { stream.writeInt32(flags); stream.writeInt64(channel_id); if ((flags & 1) != 0) { - stream.writeInt32(topic_id); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(order.get(a)); + } } } } + public static class TL_updateChannelPinnedTopic extends Update { + public static int constructor = 0x192efbe3; + + public int flags; + public boolean pinned; + public long channel_id; + public int topic_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 1) != 0; + channel_id = stream.readInt64(exception); + topic_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(channel_id); + stream.writeInt32(topic_id); + } + } + public static class TL_receivedNotifyMessage extends TLObject { public static int constructor = 0xa384b779; @@ -61570,6 +61633,7 @@ public class TLRPC { public static class TL_dialog extends Dialog { public static int constructor = 0xa8edd0f5; + public int stableId = MessagesController.stableIdPointer++; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); @@ -64032,11 +64096,9 @@ public class TLRPC { } } - public static class TL_forumTopicDeleted extends ForumTopic { + public static class TL_forumTopicDeleted extends TL_forumTopic { public static int constructor = 0x23f109b; - public int id; - public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt32(exception); } @@ -64103,6 +64165,7 @@ public class TLRPC { public boolean my; public boolean closed; public boolean pinned; + public boolean isShort; public int id; public int date; public String title; @@ -64121,10 +64184,14 @@ public class TLRPC { public ArrayList groupedMessages; // custom public Message topMessage; // custom public String searchQuery; //custom + public int pinnedOrder; // custom public static TL_forumTopic TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { TL_forumTopic result = null; switch (constructor) { + case 0x23f109b: + result = new TL_forumTopicDeleted(); + break; case 0x5920d6dc: result = new TL_forumTopic_layer147(); break; @@ -64146,6 +64213,7 @@ public class TLRPC { my = (flags & 2) != 0; closed = (flags & 4) != 0; pinned = (flags & 8) != 0; + isShort = (flags & 32) != 0; id = stream.readInt32(exception); date = stream.readInt32(exception); title = stream.readString(exception); @@ -64171,6 +64239,7 @@ public class TLRPC { flags = my ? (flags | 2) : (flags &~ 2); flags = closed ? (flags | 4) : (flags &~ 4); flags = pinned ? (flags | 8) : (flags &~ 8); + flags = isShort ? (flags | 32) : (flags &~ 32); stream.writeInt32(flags); stream.writeInt32(id); stream.writeInt32(date); @@ -64614,6 +64683,32 @@ public class TLRPC { channel.serializeToStream(stream); } } + + public static class TL_channels_reorderPinnedForumTopics extends TLObject { + public static int constructor = 0x2950a18f; + + public int flags; + public boolean force; + public InputChannel channel; + public ArrayList order = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = force ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + channel.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(order.get(a)); + } + } + } //functions public static class Vector extends TLObject { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index e999fc926..ebdff451a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -78,7 +78,7 @@ public class ActionBar extends FrameLayout { private int actionModeColor; private int actionBarColor; private boolean isMenuOffsetSuppressed; - private ActionBarMenu menu; + public ActionBarMenu menu; private ActionBarMenu actionMode; private String actionModeTag; private boolean ignoreLayoutRequest; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index e63775a11..34d99e5bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -2957,6 +2957,7 @@ public class Theme { public static Drawable dialogs_mentionDrawable; public static Drawable dialogs_reactionsMentionDrawable; public static Drawable dialogs_holidayDrawable; + public static Drawable dialogs_forum_arrowDrawable; public static RLottieDrawable dialogs_archiveAvatarDrawable; public static RLottieDrawable dialogs_archiveDrawable; public static RLottieDrawable dialogs_unarchiveDrawable; @@ -3039,6 +3040,7 @@ public class Theme { public static TextPaint chat_forwardNamePaint; public static TextPaint chat_replyNamePaint; public static TextPaint chat_replyTextPaint; + public static TextPaint chat_topicTextPaint; public static TextPaint chat_commentTextPaint; public static TextPaint chat_contextResult_titleTextPaint; public static TextPaint chat_contextResult_descriptionTextPaint; @@ -3229,6 +3231,7 @@ public class Theme { public static final String key_windowBackgroundWhiteRedText4 = "windowBackgroundWhiteRedText4"; public static final String key_windowBackgroundWhiteRedText5 = "windowBackgroundWhiteRedText5"; public static final String key_windowBackgroundWhiteRedText6 = "windowBackgroundWhiteRedText6"; + public static final String key_windowBackgroundWhiteYellowText = "windowBackgroundWhiteYellowText"; public static final String key_windowBackgroundWhiteGrayText = "windowBackgroundWhiteGrayText"; public static final String key_windowBackgroundWhiteGrayText2 = "windowBackgroundWhiteGrayText2"; public static final String key_windowBackgroundWhiteGrayText3 = "windowBackgroundWhiteGrayText3"; @@ -3294,6 +3297,7 @@ public class Theme { public static final String key_avatar_text = "avatar_text"; public static final String key_avatar_backgroundSaved = "avatar_backgroundSaved"; + public static final String key_avatar_background2Saved = "avatar_background2Saved"; public static final String key_avatar_backgroundArchived = "avatar_backgroundArchived"; public static final String key_avatar_backgroundArchivedHidden = "avatar_backgroundArchivedHidden"; public static final String key_avatar_backgroundRed = "avatar_backgroundRed"; @@ -3303,6 +3307,13 @@ public class Theme { public static final String key_avatar_backgroundCyan = "avatar_backgroundCyan"; public static final String key_avatar_backgroundBlue = "avatar_backgroundBlue"; public static final String key_avatar_backgroundPink = "avatar_backgroundPink"; + public static final String key_avatar_background2Red = "avatar_background2Red"; + public static final String key_avatar_background2Orange = "avatar_background2Orange"; + public static final String key_avatar_background2Violet = "avatar_background2Violet"; + public static final String key_avatar_background2Green = "avatar_background2Green"; + public static final String key_avatar_background2Cyan = "avatar_background2Cyan"; + public static final String key_avatar_background2Blue = "avatar_background2Blue"; + public static final String key_avatar_background2Pink = "avatar_background2Pink"; public static final String key_avatar_backgroundInProfileBlue = "avatar_backgroundInProfileBlue"; public static final String key_avatar_backgroundActionBarBlue = "avatar_backgroundActionBarBlue"; @@ -3319,6 +3330,7 @@ public class Theme { public static final String key_avatar_nameInMessagePink = "avatar_nameInMessagePink"; public static String[] keys_avatar_background = {key_avatar_backgroundRed, key_avatar_backgroundOrange, key_avatar_backgroundViolet, key_avatar_backgroundGreen, key_avatar_backgroundCyan, key_avatar_backgroundBlue, key_avatar_backgroundPink}; + public static String[] keys_avatar_background2 = {key_avatar_background2Red, key_avatar_background2Orange, key_avatar_background2Violet, key_avatar_background2Green, key_avatar_background2Cyan, key_avatar_background2Blue, key_avatar_background2Pink}; public static String[] keys_avatar_nameInMessage = {key_avatar_nameInMessageRed, key_avatar_nameInMessageOrange, key_avatar_nameInMessageViolet, key_avatar_nameInMessageGreen, key_avatar_nameInMessageCyan, key_avatar_nameInMessageBlue, key_avatar_nameInMessagePink}; public static final String key_actionBarDefault = "actionBarDefault"; @@ -3974,6 +3986,8 @@ public class Theme { public static final String key_premiumGradientBottomSheet1 = "premiumGradientBottomSheet1"; public static final String key_premiumGradientBottomSheet2 = "premiumGradientBottomSheet2"; public static final String key_premiumGradientBottomSheet3 = "premiumGradientBottomSheet3"; + public static final String key_topics_unreadCounter = "topics_unreadCounter"; + public static final String key_topics_unreadCounterMuted = "topics_unreadCounterMuted"; public static final String key_drawable_botInline = "drawableBotInline"; public static final String key_drawable_botLink = "drawableBotLink"; @@ -4025,7 +4039,6 @@ public class Theme { public static final String key_drawable_chat_pollHintDrawableOut = "drawable_chat_pollHintDrawableOut"; public static final String key_drawable_chat_pollHintDrawableIn = "drawable_chat_pollHintDrawableIn"; - private static final HashMap defaultChatDrawables = new HashMap<>(); private static final HashMap defaultChatDrawableColorKeys = new HashMap<>(); @@ -4138,6 +4151,7 @@ public class Theme { defaultColors.put(key_windowBackgroundWhiteRedText4, 0xffcf3030); defaultColors.put(key_windowBackgroundWhiteRedText5, 0xffed3939); defaultColors.put(key_windowBackgroundWhiteRedText6, 0xffff6666); + defaultColors.put(key_windowBackgroundWhiteYellowText, 0xffD87B29); defaultColors.put(key_windowBackgroundWhiteGrayText, 0xff838c96); defaultColors.put(key_windowBackgroundWhiteGrayText2, 0xff82868a); defaultColors.put(key_windowBackgroundWhiteGrayText3, 0xff999999); @@ -4192,16 +4206,25 @@ public class Theme { defaultColors.put(key_avatar_text, 0xffffffff); - defaultColors.put(key_avatar_backgroundSaved, 0xff66bffa); - defaultColors.put(key_avatar_backgroundArchived, 0xffa9b6c1); + defaultColors.put(key_avatar_backgroundSaved, 0xff69BFFA); + defaultColors.put(key_avatar_background2Saved, 0xff3D9DE0); + defaultColors.put(key_avatar_backgroundArchived, 0xffB8C2CC); defaultColors.put(key_avatar_backgroundArchivedHidden, 0xff66bffa); - defaultColors.put(key_avatar_backgroundRed, 0xffe56555); - defaultColors.put(key_avatar_backgroundOrange, 0xfff28c48); - defaultColors.put(key_avatar_backgroundViolet, 0xff8e85ee); - defaultColors.put(key_avatar_backgroundGreen, 0xff76c84d); - defaultColors.put(key_avatar_backgroundCyan, 0xff5fbed5); - defaultColors.put(key_avatar_backgroundBlue, 0xff549cdd); - defaultColors.put(key_avatar_backgroundPink, 0xfff2749a); + defaultColors.put(key_avatar_backgroundRed, 0xffFF845E); + defaultColors.put(key_avatar_backgroundOrange, 0xffFEBB5B); + defaultColors.put(key_avatar_backgroundViolet, 0xffB694F9); + defaultColors.put(key_avatar_backgroundGreen, 0xff9AD164); + defaultColors.put(key_avatar_backgroundCyan, 0xff5BCBE3); + defaultColors.put(key_avatar_backgroundBlue, 0xff5CAFFA); + defaultColors.put(key_avatar_backgroundPink, 0xffFF8AAC); + + defaultColors.put(key_avatar_background2Red, 0xffD45246); + defaultColors.put(key_avatar_background2Orange, 0xffF68136); + defaultColors.put(key_avatar_background2Violet, 0xff6C61DF); + defaultColors.put(key_avatar_background2Green, 0xff46BA43); + defaultColors.put(key_avatar_background2Cyan, 0xff359AD4); + defaultColors.put(key_avatar_background2Blue, 0xff408ACF); + defaultColors.put(key_avatar_background2Pink, 0xffD95574); defaultColors.put(key_avatar_backgroundInProfileBlue, 0xff5085b1); defaultColors.put(key_avatar_backgroundActionBarBlue, 0xff598fba); @@ -4211,11 +4234,11 @@ public class Theme { defaultColors.put(key_avatar_nameInMessageRed, 0xffca5650); defaultColors.put(key_avatar_nameInMessageOrange, 0xffd87b29); - defaultColors.put(key_avatar_nameInMessageViolet, 0xff4e92cc); + defaultColors.put(key_avatar_nameInMessageViolet, 0xff9B66DC); defaultColors.put(key_avatar_nameInMessageGreen, 0xff50b232); defaultColors.put(key_avatar_nameInMessageCyan, 0xff379eb8); defaultColors.put(key_avatar_nameInMessageBlue, 0xff4e92cc); - defaultColors.put(key_avatar_nameInMessagePink, 0xff4e92cc); + defaultColors.put(key_avatar_nameInMessagePink, 0xffCF5C95); defaultColors.put(key_actionBarDefault, 0xff527da3); defaultColors.put(key_actionBarDefaultIcon, 0xffffffff); @@ -4867,6 +4890,8 @@ public class Theme { defaultColors.put(key_premiumGradientBottomSheet1, 0xff5B9DE7); defaultColors.put(key_premiumGradientBottomSheet2, 0xffAB87DD); defaultColors.put(key_premiumGradientBottomSheet3, 0xffE794BE); + defaultColors.put(key_topics_unreadCounter, 0xff4ecc5e); + defaultColors.put(key_topics_unreadCounterMuted, 0xff8b8d8f); fallbackKeys.put(key_chat_inAdminText, key_chat_inTimeText); fallbackKeys.put(key_chat_inAdminSelectedText, key_chat_inTimeSelectedText); @@ -4984,6 +5009,7 @@ public class Theme { fallbackKeys.put(key_chat_outPollCorrectAnswer, key_chat_attachLocationBackground); fallbackKeys.put(key_chat_inPollWrongAnswer, key_chat_attachAudioBackground); fallbackKeys.put(key_chat_outPollWrongAnswer, key_chat_attachAudioBackground); + fallbackKeys.put(key_windowBackgroundWhiteYellowText, key_avatar_nameInMessageOrange); fallbackKeys.put(key_profile_tabText, key_windowBackgroundWhiteGrayText); fallbackKeys.put(key_profile_tabSelectedText, key_windowBackgroundWhiteBlueHeader); @@ -5014,8 +5040,19 @@ public class Theme { fallbackKeys.put(key_chat_inReactionButtonTextSelected, key_windowBackgroundWhite); fallbackKeys.put(key_chat_outReactionButtonTextSelected, key_windowBackgroundWhite); fallbackKeys.put(key_dialogReactionMentionBackground, key_voipgroup_mutedByAdminGradient2); + fallbackKeys.put(key_topics_unreadCounter, key_chats_unreadCounter); + fallbackKeys.put(key_topics_unreadCounterMuted, key_chats_message); + + fallbackKeys.put(key_avatar_background2Red, key_avatar_backgroundRed); + fallbackKeys.put(key_avatar_background2Orange, key_avatar_backgroundOrange); + fallbackKeys.put(key_avatar_background2Violet, key_avatar_backgroundViolet); + fallbackKeys.put(key_avatar_background2Green, key_avatar_backgroundGreen); + fallbackKeys.put(key_avatar_background2Cyan, key_avatar_backgroundCyan); + fallbackKeys.put(key_avatar_background2Blue, key_avatar_backgroundBlue); + fallbackKeys.put(key_avatar_background2Pink, key_avatar_backgroundPink); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background)); + themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_background2)); themeAccentExclusionKeys.addAll(Arrays.asList(keys_avatar_nameInMessage)); themeAccentExclusionKeys.add(key_chat_attachFileBackground); themeAccentExclusionKeys.add(key_chat_attachGalleryBackground); @@ -8924,6 +8961,7 @@ public class Theme { dialogs_mentionDrawable = resources.getDrawable(R.drawable.mentionchatslist); dialogs_reactionsMentionDrawable = resources.getDrawable(R.drawable.reactionchatslist); dialogs_pinnedDrawable = resources.getDrawable(R.drawable.list_pin); + dialogs_forum_arrowDrawable = resources.getDrawable(R.drawable.msg_mini_forumarrow); moveUpDrawable = resources.getDrawable(R.drawable.preview_arrow); RectF rect = new RectF(); @@ -8997,6 +9035,7 @@ public class Theme { setDrawableColorByKey(dialogs_muteDrawable, key_chats_muteIcon); setDrawableColorByKey(dialogs_unmuteDrawable, key_chats_muteIcon); setDrawableColorByKey(dialogs_mentionDrawable, key_chats_mentionIcon); + setDrawableColorByKey(dialogs_forum_arrowDrawable, key_chats_message); setDrawableColorByKey(dialogs_reactionsMentionDrawable, key_chats_mentionIcon); setDrawableColorByKey(dialogs_verifiedDrawable, key_chats_verifiedBackground); setDrawableColorByKey(dialogs_verifiedCheckDrawable, key_chats_verifiedCheck); @@ -9042,6 +9081,8 @@ public class Theme { chat_replyNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + chat_topicTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_adminPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); @@ -9062,6 +9103,7 @@ public class Theme { chat_namePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_replyNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_replyTextPaint.setTextSize(AndroidUtilities.dp(smallerDp)); + chat_topicTextPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); chat_forwardNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_adminPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); // float timeDp = 2 * (SharedConfig.fontSize - 16) / 3f + 12; @@ -9122,6 +9164,8 @@ public class Theme { chat_replyNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_replyNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + chat_topicTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + chat_topicTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); chat_commentTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); chat_instantViewPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); chat_instantViewPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); @@ -9462,6 +9506,7 @@ public class Theme { chat_namePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_replyNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_replyTextPaint.setTextSize(AndroidUtilities.dp(smallerDp)); + chat_topicTextPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); chat_forwardNamePaint.setTextSize(AndroidUtilities.dp(smallerDp)); chat_adminPaint.setTextSize(AndroidUtilities.dp(smallerDp - 1)); float timeDp = 2 * (SharedConfig.fontSize - 16) / 3f + 12; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index 4d15e58f9..a073c9819 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -17,7 +17,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.SystemClock; -import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -66,7 +65,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -public class DialogsAdapter extends RecyclerListView.SelectionAdapter { +public class DialogsAdapter extends RecyclerListView.SelectionAdapter implements DialogCell.DialogCellDelegate { public final static int VIEW_TYPE_DIALOG = 0, VIEW_TYPE_FLICKER = 1, VIEW_TYPE_RECENTLY_VIEWED = 2, @@ -413,6 +412,7 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { DialogCell dialogCell = new DialogCell(parentFragment, mContext, true, false, currentAccount, null); dialogCell.setArchivedPullAnimation(pullForegroundDrawable); dialogCell.setPreloader(preloader); + dialogCell.setDialogCellDelegate(this); view = dialogCell; } break; @@ -887,6 +887,21 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } } + @Override + public void onButtonClicked(DialogCell dialogCell) { + + } + + @Override + public void onButtonLongPress(DialogCell dialogCell) { + + } + + @Override + public boolean canClickButtonInside() { + return selectedDialogs.isEmpty(); + } + public static class DialogsPreloader { private final int MAX_REQUEST_COUNT = 4; @@ -1063,6 +1078,5 @@ public class DialogsAdapter extends RecyclerListView.SelectionAdapter { } setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height); } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index 78b84a62f..4e42ab0be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -1035,7 +1035,12 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { view = new GraySectionCell(mContext); break; case VIEW_TYPE_DIALOG_CELL: - view = new DialogCell(null, mContext, false, true); + view = new DialogCell(null, mContext, false, true) { + @Override + protected boolean isForumCell() { + return false; + } + }; break; case VIEW_TYPE_LOADING: FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index 36ddeeae5..83c4b1441 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -10554,7 +10554,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg progressView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(39), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(39), MeasureSpec.EXACTLY)); imageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(39), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(39), MeasureSpec.EXACTLY)); if (currentBlock != null) { - textLayout = createLayoutForText(this, currentBlock.channel.title, null, width - AndroidUtilities.dp(36 + 16) - buttonWidth, textY, currentBlock, StaticLayoutEx.ALIGN_LEFT(), parentAdapter); + textLayout = createLayoutForText(this, currentBlock.channel.title, null, width - AndroidUtilities.dp(36 + 16) - buttonWidth, textY, currentBlock, StaticLayoutEx.ALIGN_LEFT(), 1, parentAdapter); if (parentAdapter.isRtl) { textX2 = textX; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index e1d02ab38..79b92626b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -75,6 +75,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; +import androidx.core.math.MathUtils; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AccountInstance; @@ -112,6 +113,7 @@ import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AnimatedColor; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AnimatedFileDrawable; @@ -127,10 +129,10 @@ import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmptyStubSpan; import org.telegram.ui.Components.FloatSeekBarAccessibilityDelegate; import org.telegram.ui.Components.Forum.ForumUtilities; +import org.telegram.ui.Components.Forum.MessageTopicButton; import org.telegram.ui.Components.InfiniteProgress; import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.LinkSpanDrawable; -import org.telegram.ui.Components.LocationMessageLoadingDrawable; import org.telegram.ui.Components.MediaActionDrawable; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.MotionBackgroundDrawable; @@ -523,6 +525,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate default boolean didPressAnimatedEmoji(AnimatedEmojiSpan span) { return false; } + + default void didPressTopicButton(ChatMessageCell cell) {} } private final static int DOCUMENT_ATTACH_TYPE_NONE = 0; @@ -961,6 +965,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float replyTouchX, replyTouchY; private TLRPC.PhotoSize currentReplyPhoto; + private boolean drawTopic; + private MessageTopicButton topicButton; + private int drawSideButton; private boolean sideButtonPressed; private float sideStartX; @@ -1237,7 +1244,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate pollAvatarImages[a] = new ImageReceiver(this); pollAvatarImages[a].setRoundRadius(AndroidUtilities.dp(8)); pollAvatarDrawables[a] = new AvatarDrawable(); - pollAvatarDrawables[a].setTextSize(AndroidUtilities.dp(6)); + pollAvatarDrawables[a].setTextSize(AndroidUtilities.dp(22)); } pollCheckBox = new CheckBoxBase[10]; for (int a = 0; a < pollCheckBox.length; a++) { @@ -2645,6 +2652,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!result) { result = checkTextSelection(event); } + if (!result && topicButton != null) { + result = topicButton.checkTouchEvent(event); + } if (!result) { result = checkOtherButtonMotionEvent(event); } @@ -3692,6 +3702,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate unregisterFlagSecure.run(); unregisterFlagSecure = null; } + + if (topicButton != null) { + topicButton.onDetached(this); + } } @Override @@ -3763,6 +3777,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_EXTENDED_MEDIA_PREVIEW && unlockLayout != null) { invalidate(); } + + if (topicButton != null) { + topicButton.onAttached(this); + } } boolean imageReceiversAttachState; @@ -4501,6 +4519,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int maxChildWidth = Math.max(backgroundWidth, nameWidth); maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); maxChildWidth = Math.max(maxChildWidth, replyNameWidth); + if (topicButton != null) { + maxChildWidth = Math.max(maxChildWidth, topicButton.width()); + } maxChildWidth = Math.max(maxChildWidth, replyTextWidth); if (commentLayout != null && drawSideButton != 3) { maxChildWidth = Math.max(maxChildWidth, totalCommentWidth); @@ -4563,7 +4584,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate "telegram_user".equals(type) || "telegram_channel".equals(type) || "telegram_megagroup".equals(type) || "telegram_voicechat".equals(type) || "telegram_livestream".equals(type); - smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13) && document == null && isSmallImageType; + smallImage = !slideshow && (!drawInstantView || drawInstantViewType == 1 || drawInstantViewType == 2 || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13) && document == null && isSmallImageType; isSmallImage = smallImage && type != null && currentMessageObject.photoThumbs != null; } else if (hasInvoicePreview) { TLRPC.TL_messageMediaInvoice invoice = (TLRPC.TL_messageMediaInvoice) MessageObject.getMedia(messageObject.messageOwner); @@ -6114,13 +6135,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentMapProvider = MessagesController.getInstance(messageObject.currentAccount).mapProvider; } if (locationLoadingThumb == null) { - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(R.raw.map_placeholder, Theme.key_windowBackgroundWhiteGrayIcon, 1f); + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(R.raw.map_placeholder, Theme.key_chat_outLocationIcon, (Theme.isCurrentThemeDark() ? 3 : 6) * .12f); svgThumb.setAspectCenter(true); locationLoadingThumb = new ClipRoundedDrawable(svgThumb); } if (locationLoadingThumb instanceof ClipRoundedDrawable && ((ClipRoundedDrawable) locationLoadingThumb).getDrawable() instanceof SvgHelper.SvgDrawable) { SvgHelper.SvgDrawable drawable = (SvgHelper.SvgDrawable) ((ClipRoundedDrawable) locationLoadingThumb).getDrawable(); - drawable.setColorKey(messageObject.isOutOwner() ? Theme.key_chat_outBubbleLocationPlaceholder : Theme.key_chat_inBubbleLocationPlaceholder); + drawable.setColorKey(messageObject.isOutOwner() ? Theme.key_chat_outLocationIcon : Theme.key_chat_inLocationIcon, resourcesProvider); } photoImage.setCrossfadeDuration(2 * ImageReceiver.DEFAULT_CROSSFADE_DURATION); photoImage.setCrossfadeByScale(.05f); @@ -6176,7 +6197,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate additionHeight += reactionsLayoutInBubble.totalHeight + AndroidUtilities.dp(8); reactionsLayoutInBubble.positionOffsetY += AndroidUtilities.dp(8); } - additionHeight -= AndroidUtilities.dp(17); + if (!(drawTopic && (currentMessageObject != null && currentMessageObject.replyMessageObject != null || forwardedNameLayout != null && forwardedNameLayout[0] != null))) { + additionHeight -= AndroidUtilities.dp(17); + } } else if (messageObject.isAnyKindOfSticker()) { drawBackground = false; @@ -6970,13 +6993,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { photoHeight += AndroidUtilities.dp(1); } + } else if (currentPosition != null && currentMessageObject.isDocument()) { + if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0 && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 && !messageObject.isOutOwner()) { + totalHeight -= AndroidUtilities.dp(2); + } } int y = 0; if (currentMessageObject.type != MessageObject.TYPE_EMOJIS) { if (drawPinnedTop) { - namesOffset -= AndroidUtilities.dp(1); + namesOffset -= AndroidUtilities.dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 1); } + if (drawPinnedTop && !messageObject.isOutOwner()) { + totalHeight += AndroidUtilities.dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 2 : 0); + } +// if (drawPinnedBottom && !messageObject.isOutOwner()) { +// totalHeight += AndroidUtilities.dp(documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT ? 1 : 0); +// } if (namesOffset > 0) { y = AndroidUtilities.dp(7); totalHeight -= AndroidUtilities.dp(2); @@ -7542,6 +7575,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (replySelector != null) { replySelector.setState(new int[]{}); } + if (topicButton != null) { + topicButton.resetClick(); + } if (pressedEmoji != null) { // hadLongPress = true; // if (delegate.didPressAnimatedEmoji(pressedEmoji)) { @@ -7682,6 +7718,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ); } + public void invalidateOutbounds() { + if (delegate == null || !delegate.canDrawOutboundsContent()) { + if (getParent() instanceof View) { + ((View) getParent()).invalidate(); + } + } else { + super.invalidate(); + } + } + @Override public void invalidate() { if (currentMessageObject == null) { @@ -9786,7 +9832,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate linkPreviewY += currentMessageObject.textHeight + AndroidUtilities.dp(4); } - if (drawPhotoImage && drawInstantView && drawInstantViewType != 9 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 || drawInstantViewType == 6 && imageBackgroundColor != 0) { + if (drawPhotoImage && drawInstantView && drawInstantViewType != 9 && drawInstantViewType != 2 && drawInstantViewType != 13 && drawInstantViewType != 11 && drawInstantViewType != 1 || drawInstantViewType == 6 && imageBackgroundColor != 0) { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } @@ -9919,7 +9965,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); } - if (drawPhotoImage && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1)) { + if (drawPhotoImage && (!drawInstantView || drawInstantViewType == 9 || drawInstantViewType == 2 || drawInstantViewType == 11 || drawInstantViewType == 13 || drawInstantViewType == 1)) { if (linkPreviewY != startY) { linkPreviewY += AndroidUtilities.dp(2); } @@ -10344,7 +10390,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject == null || currentMessageObject != null && currentMessageObject.hasExtendedMedia()) { return MediaActionDrawable.ICON_NONE; } - if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject.isVoiceTranscriptionOpen() && (currentMessageObject != null && currentMessageObject.attachPathExists && !TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath) || currentMessageObject.mediaExists)) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject.isVoiceTranscriptionOpen() && canStreamVideo) { if (buttonState == 1 || buttonState == 4) { return MediaActionDrawable.ICON_PAUSE; } @@ -10529,7 +10575,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean fromBot = currentMessageObject.messageOwner.params != null && currentMessageObject.messageOwner.params.containsKey("query_id"); - if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen() && fileExists) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND && currentMessageObject != null && currentMessageObject.isVoiceTranscriptionOpen() && canStreamVideo) { if (currentMessageObject.isOut() && (currentMessageObject.isSending() && !currentMessageObject.isForwarded() || currentMessageObject.isEditing() && currentMessageObject.isEditingMedia()) || currentMessageObject.isSendError() && fromBot) { if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { DownloadController.getInstance(currentAccount).addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); @@ -11886,6 +11932,42 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + drawTopic = false; + if (!isThreadChat && !pinnedTop && (MessageObject.getTopicId(messageObject.messageOwner) != 0 || messageObject.replyToForumTopic != null)) { + if (currentPosition == null || currentPosition.minY == 0) { + int topicId = MessageObject.getTopicId(messageObject.messageOwner); + TLRPC.TL_forumTopic topic = messageObject.replyToForumTopic == null ? MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), topicId) : messageObject.replyToForumTopic; + if (topic != null) { + drawTopic = true; + + int maxWidth = getMaxNameWidth(); + if (!messageObject.shouldDrawWithoutBackground()) { + maxWidth -= AndroidUtilities.dp(10); + } else if (messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { + maxWidth += AndroidUtilities.dp(13 + 35); + } else if (messageObject.isAnyKindOfSticker()) { + maxWidth += AndroidUtilities.dp(25); + } + + if (topicButton == null) { + topicButton = new MessageTopicButton(getContext(), resourcesProvider) { + @Override + protected void onClick() { + if (delegate != null) { + delegate.didPressTopicButton(ChatMessageCell.this); + } + } + }; + } + namesOffset += topicButton.set(this, messageObject, topic, maxWidth); + } + } + } + if (!drawTopic && topicButton != null) { + topicButton.onDetached(this); + topicButton = null; + } + if ((!isThreadChat || messageObject.getReplyTopMsgId() != 0) && messageObject.hasValidReplyMessageObject() || messageObject.messageOwner.fwd_from != null && messageObject.isDice()) { if (currentPosition == null || currentPosition.minY == 0) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { @@ -12005,16 +12087,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate mess = mess.replace('\n', ' '); stringFinalText = Emoji.replaceEmoji(mess, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); if (messageObject.replyMessageObject.messageOwner != null) { - stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, Theme.chat_replyTextPaint.getFontMetricsInt()); + stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, Theme.chat_replyTextPaint.getFontMetricsInt(), true); } stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable && messageObject.replyMessageObject.messageOwner != null) { MediaDataController.addTextStyleRuns(messageObject.replyMessageObject.messageOwner.entities, messageObject.replyMessageObject.caption, (Spannable) stringFinalText); } - } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate) { - TLRPC.TL_messageActionTopicCreate topicCreate = (TLRPC.TL_messageActionTopicCreate) messageObject.replyMessageObject.messageOwner.action; - TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-messageObject.getDialogId(), messageObject.replyMessageObject.messageOwner.id); - stringFinalText = ForumUtilities.getTopicSpannedName(topic, Theme.chat_replyTextPaint); } else if (messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageText != null && messageObject.replyMessageObject.messageText.length() > 0) { String mess = messageObject.replyMessageObject.messageText.toString(); if (mess.length() > 150) { @@ -12023,7 +12101,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate mess = mess.replace('\n', ' '); stringFinalText = Emoji.replaceEmoji(mess, Theme.chat_replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); if (messageObject.replyMessageObject.messageOwner != null) { - stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, Theme.chat_replyTextPaint.getFontMetricsInt()); + stringFinalText = MessageObject.replaceAnimatedEmoji(stringFinalText, messageObject.replyMessageObject.messageOwner.entities, Theme.chat_replyTextPaint.getFontMetricsInt(), true); } stringFinalText = TextUtils.ellipsize(stringFinalText, Theme.chat_replyTextPaint, maxWidth, TextUtils.TruncateAt.END); if (stringFinalText instanceof Spannable) { @@ -12107,8 +12185,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate replyTextOffset = (int) replyTextLayout.getLineLeft(0); } replySpoilers.clear(); - if (getMessageObject().replyMessageObject != null && !getMessageObject().replyMessageObject.isSpoilersRevealed) + if (getMessageObject().replyMessageObject != null && !getMessageObject().replyMessageObject.isSpoilersRevealed) { SpoilerEffect.addSpoilers(this, replyTextLayout, replySpoilersPool, replySpoilers); + } animatedEmojiReplyStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, false, animatedEmojiReplyStack, replyTextLayout); } } catch (Exception e) { @@ -12116,7 +12195,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } else if (!isThreadChat && messageObject.getReplyMsgId() != 0) { - if (!(messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty)) { + if (!(messageObject.replyMessageObject != null && (messageObject.replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty || messageObject.replyMessageObject.messageOwner != null && messageObject.replyMessageObject.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate))) { if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { namesOffset += AndroidUtilities.dp(14) + (Theme.chat_replyTextPaint.getTextSize() + Theme.chat_replyNamePaint.getTextSize()); if (messageObject.type != MessageObject.TYPE_TEXT) { @@ -12451,6 +12530,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate replyStartY = forwardNameY + forwardHeight + AndroidUtilities.dp(6); } else { replyStartY = AndroidUtilities.dp(12); + if (drawTopic && topicButton != null) { + replyStartY += topicButton.height() + AndroidUtilities.dp(10); + } } } else { if (currentMessageObject.isOutOwner()) { @@ -12464,6 +12546,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } forwardHeight = AndroidUtilities.dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; replyStartY = AndroidUtilities.dp(12) + (drawNameLayout && nameLayout != null ? AndroidUtilities.dp(6) + (int) Theme.chat_namePaint.getTextSize() : 0) + (drawForwardedName && forwardedNameLayout[0] != null ? AndroidUtilities.dp(4) + forwardHeight : 0); + if (drawTopic && topicButton != null) { + replyStartY += topicButton.height() + AndroidUtilities.dp(5); + } } } if (currentPosition == null && !transitionParams.animateBackgroundBoundsInner && !(enterTransitionInProgress && !currentMessageObject.isVoice())) { @@ -13004,6 +13089,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawSideButton != 0 || drawNameLayout && nameLayout != null && currentNameStatusDrawable != null && currentNameStatusDrawable.getDrawable() != null || animatedEmojiStack != null && !animatedEmojiStack.holders.isEmpty() || + drawTopic && topicButton != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) || currentMessagesGroup == null && (transitionParams.animateReplaceCaptionLayout && transitionParams.animateChangeProgress != 1f || transitionParams.animateChangeProgress != 1.0f && transitionParams.animateMessageText) && transitionParams.animateOutAnimateEmoji != null && !transitionParams.animateOutAnimateEmoji.holders.isEmpty() @@ -13079,6 +13165,31 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentNameStatusDrawable.draw(canvas); } + if (drawTopic && topicButton != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { + float replyForwardAlpha = 1f; + if (isRoundVideo && !hasLinkPreview) { + replyForwardAlpha *= 1f - getVideoTranscriptionProgress(); + if (transitionParams.animatePlayingRound) { + if (isPlayingRound) { + replyForwardAlpha *= (1f - transitionParams.animateChangeProgress); + } else { + replyForwardAlpha *= transitionParams.animateChangeProgress; + } + } else if (isPlayingRound) { + replyForwardAlpha = 0; + } + } + float animatingAlpha = 1f; + if (transitionParams.animateForwardedLayout) { + if (!currentMessageObject.needDrawForwarded()) { + animatingAlpha = 1f - transitionParams.animateChangeProgress; + } else { + animatingAlpha = transitionParams.animateChangeProgress; + } + } + topicButton.drawOutbounds(canvas, animatingAlpha * replyForwardAlpha); + } + if (!transitionParams.transitionBotButtons.isEmpty() && transitionParams.animateBotButtonsChanged) { drawBotButtons(canvas, transitionParams.transitionBotButtons, 1f - transitionParams.animateChangeProgress); } @@ -13433,13 +13544,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public boolean hasNameLayout() { return drawNameLayout && nameLayout != null || drawForwardedName && forwardedNameLayout[0] != null && forwardedNameLayout[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) || - replyNameLayout != null; + replyNameLayout != null || drawTopic; } public boolean isDrawNameLayout() { return drawNameLayout && nameLayout != null; } + public boolean isDrawTopic() { + return drawTopic; + } + + public float getDrawTopicHeight() { + return topicButton != null ? topicButton.height() : 0; + } + public boolean isAdminLayoutChanged() { return !TextUtils.equals(lastPostAuthor, currentMessageObject.messageOwner.post_author); } @@ -13657,7 +13776,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!currentMessageObject.isVoiceTranscriptionOpen() && (currentMessageObject.isOutOwner() && currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO && transitionParams.animatePlayingRound || isPlayingRound)) { forwardNameXLocal -= AndroidUtilities.dp(78) * (isPlayingRound ? transitionParams.animateChangeProgress : (1f - transitionParams.animateChangeProgress)); } - forwardNameY = AndroidUtilities.dp(12); + forwardNameY = AndroidUtilities.dp(12) + (drawTopic && topicButton != null ? topicButton.height() + AndroidUtilities.dp(14) : 0); forwardHeight = AndroidUtilities.dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; int backWidth = forwardedNameWidthLocal + AndroidUtilities.dp(14); @@ -13689,7 +13808,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); } } else { - forwardNameY = AndroidUtilities.dp(10) + (drawNameLayout ? AndroidUtilities.dp(5) + (int) Theme.chat_namePaint.getTextSize() : 0); + forwardNameY = AndroidUtilities.dp(10) + (drawNameLayout ? AndroidUtilities.dp(5) + (int) Theme.chat_namePaint.getTextSize() : 0) + (drawTopic && topicButton != null ? topicButton.height() + AndroidUtilities.dp(7 + (currentMessageObject.type != MessageObject.TYPE_TEXT ? 3 : 0)) : 0); forwardHeight = AndroidUtilities.dp(4) + (int) Theme.chat_forwardNamePaint.getTextSize() * 2; if (currentMessageObject.isOutOwner()) { if (hasPsaHint) { @@ -13793,6 +13912,37 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + if (drawTopic && (animatingAlpha > 0 && replyForwardAlpha > 0) && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0)) { + float x, y; + if (currentMessageObject.shouldDrawWithoutBackground()) { + if (currentMessageObject.isOutOwner()) { + x = AndroidUtilities.dp(23); + if (isPlayingRound) { + x -= (AndroidUtilities.roundPlayingMessageSize - AndroidUtilities.roundMessageSize); + } + } else if (currentMessageObject.type == MessageObject.TYPE_ROUND_VIDEO) { + x = backgroundDrawableLeft + backgroundDrawableRight + AndroidUtilities.dp(4); + } else { + x = backgroundDrawableLeft + backgroundDrawableRight + AndroidUtilities.dp(17); + } + y = AndroidUtilities.dp(12); + x -= AndroidUtilities.dp(8); + } else { + if (currentMessageObject.isOutOwner()) { + x = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); + } else { + if (mediaBackground) { + x = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); + } else { + x = backgroundDrawableLeft + AndroidUtilities.dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); + } + } + x -= AndroidUtilities.dp(2.33f); + y = AndroidUtilities.dp(12) + (drawNameLayout && nameLayout != null ? AndroidUtilities.dp(6) + (int) Theme.chat_namePaint.getTextSize() : 0); + } + topicButton.draw(canvas, x, y, animatingAlpha * replyForwardAlpha); + } + if (hasReply) { float replyStartX = this.replyStartX; float replyStartY = this.replyStartY; @@ -13879,14 +14029,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate (int) (replyStartY + replyHeight + AndroidUtilities.dp(7)) ); } else { - if (drawNameLayout || (drawForwardedName && forwardedNameLayout[0] != null)) { + if (drawTopic || drawNameLayout || (drawForwardedName && forwardedNameLayout[0] != null)) { leftRad = bottomRad; } else if (currentMessageObject.isOutOwner() || !drawPinnedTop) { leftRad = AndroidUtilities.dp(SharedConfig.bubbleRadius / 3f); } else { leftRad = AndroidUtilities.dp(Math.min(6, SharedConfig.bubbleRadius) / 3f); } - if (drawNameLayout || (drawForwardedName && forwardedNameLayout[0] != null)) { + if (drawTopic || drawNameLayout || (drawForwardedName && forwardedNameLayout[0] != null)) { rightRad = bottomRad; } else if (!currentMessageObject.isOutOwner() || !drawPinnedTop) { rightRad = AndroidUtilities.dp(SharedConfig.bubbleRadius / 3f); @@ -14609,8 +14759,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate paint = getThemedPaint(Theme.key_paint_chatTimeBackground); } int oldAlpha = paint.getAlpha(); - paint.setAlpha((int) (oldAlpha * timeAlpha * alpha)); + float oldAlpha3 = alpha; Theme.chat_timePaint.setAlpha((int) (255 * timeAlpha * alpha)); + if (currentMessageObject != null && currentMessageObject.type == MessageObject.TYPE_GEO) { + float progress = photoImage.isCrossfadingWithOldImage() ? 1 : photoImage.getCurrentAlpha(); + if (!photoImage.hasNotThumb()) { + progress = 0; + } + alpha = AndroidUtilities.lerp(0.35f, 1f, progress); + } + paint.setAlpha((int) (oldAlpha * timeAlpha * alpha)); int r; if (documentAttachType != DOCUMENT_ATTACH_TYPE_ROUND && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER && currentMessageObject.type != MessageObject.TYPE_EMOJIS) { @@ -14641,6 +14799,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } paint.setAlpha(oldAlpha); + alpha = oldAlpha3; + float additionalX = -timeLayout.getLineLeft(0); if (reactionsLayoutInBubble.isSmall) { updateReactionLayoutPosition(); @@ -15705,9 +15865,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } float progress = photoImage.isCrossfadingWithOldImage() ? 1 : photoImage.getCurrentAlpha(); - if (progress > 0 && photoImage.hasNotThumb()) { + if (progress > 0 && (photoImage.hasNotThumb() || photoImage.isCrossfadingWithOldImage())) { int cx = (int) (photoImage.getImageX() + photoImage.getImageWidth() / 2 - AndroidUtilities.dp(31)); - cy = (int) (photoImage.getImageY() + photoImage.getImageHeight() / 2 - AndroidUtilities.dp(38) - AndroidUtilities.dp(16) * (1f - CubicBezierInterpolator.EASE_OUT_BACK.getInterpolation(photoImage.getCurrentAlpha()))); + cy = (int) (photoImage.getImageY() + photoImage.getImageHeight() / 2 - AndroidUtilities.dp(38) - AndroidUtilities.dp(16) * (1f - CubicBezierInterpolator.EASE_OUT_BACK.getInterpolation(progress))); setDrawableBounds(Theme.chat_msgAvatarLiveLocationDrawable, cx, cy); Theme.chat_msgAvatarLiveLocationDrawable.setAlpha((int) (255 * Math.min(1, progress * 5))); @@ -16178,7 +16338,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean restore = false; boolean on = false; - if (currentMessageObject != null && currentMessageObject.isRoundVideo() && (getVideoTranscriptionProgress() <= 0 && !currentMessageObject.mediaExists)) { + if (currentMessageObject != null && currentMessageObject.isRoundVideo() && !currentMessageObject.mediaExists) { radialProgress.setProgressRect( photoImage.getImageX() + (photoImage.getImageWidth() - radialProgress.getRadius()) / 2f, photoImage.getImageY() + (photoImage.getImageHeight() - radialProgress.getRadius()) / 2f, diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index b1ff552d8..d2a8cf19e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -37,12 +37,14 @@ import android.text.style.ClickableSpan; import android.text.style.ReplacementSpan; import android.text.style.StyleSpan; import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; import android.view.animation.OvershootInterpolator; import androidx.core.content.ContextCompat; +import androidx.core.graphics.ColorUtils; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; @@ -71,6 +73,7 @@ import org.telegram.ui.Adapters.DialogsAdapter; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.AnimatedEmojiSpan; import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.CanvasButton; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -93,6 +96,7 @@ import org.telegram.ui.DialogsActivity; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Stack; @@ -115,7 +119,16 @@ public class DialogCell extends BaseCell { private boolean isTopic; private boolean twoLinesForName; private boolean nameIsEllipsized; + private Paint topicCounterPaint; public float chekBoxPaddingTop = 42; + private boolean needEmoji; + private boolean hasNameInMessage; + private TextPaint currentMessagePaint; + private Paint buttonBackgroundPaint; + CanvasButton canvasButton; + DialogCellDelegate delegate; + private boolean applyName; + private boolean lastTopicMessageUnread; public void setMoving(boolean moving) { this.moving = moving; @@ -220,6 +233,7 @@ public class DialogCell extends BaseCell { private float dialogMutedProgress; private boolean hasUnmutedTopics = false; private MessageObject message; + private boolean isForum; private ArrayList groupMessages; private boolean clearingDialog; private CharSequence lastMessageString; @@ -228,6 +242,8 @@ public class DialogCell extends BaseCell { private int folderId; private int messageId; private boolean archiveHidden; + protected boolean forbidVerified; + protected boolean forbidDraft; private float cornerProgress; private long lastUpdateTime; @@ -313,9 +329,14 @@ public class DialogCell extends BaseCell { private int messageLeft; private StaticLayout messageLayout; + private int buttonTop; + private StaticLayout buttonLayout; + private Stack spoilersPool = new Stack<>(); private List spoilers = new ArrayList<>(); - private AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiStack, animatedEmojiStack2; + private Stack spoilersPool2 = new Stack<>(); + private List spoilers2 = new ArrayList<>(); + private AnimatedEmojiSpan.EmojiGroupedSpans animatedEmojiStack, animatedEmojiStack2, animatedEmojiStack3; private int messageNameTop; private int messageNameLeft; @@ -487,6 +508,9 @@ public class DialogCell extends BaseCell { } private boolean isOnline() { + if (isForumCell()) { + return false; + } if (user == null || user.self) { return false; } @@ -579,6 +603,7 @@ public class DialogCell extends BaseCell { } AnimatedEmojiSpan.release(this, animatedEmojiStack); AnimatedEmojiSpan.release(this, animatedEmojiStack2); + AnimatedEmojiSpan.release(this, animatedEmojiStack3); } @Override @@ -591,6 +616,7 @@ public class DialogCell extends BaseCell { resetPinnedArchiveState(); animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack, messageLayout); animatedEmojiStack2 = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack2, messageNameLayout); + animatedEmojiStack3 = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack3, buttonLayout); } public void resetPinnedArchiveState() { @@ -612,13 +638,20 @@ public class DialogCell extends BaseCell { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (checkBox != null) { - checkBox.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + checkBox.measure( + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY) + ); } if (isTopic) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (useSeparator ? 1 : 0)); checkTwoLinesForName(); } - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (useSeparator ? 1 : 0) + (twoLinesForName ? AndroidUtilities.dp(20) : 0)); + if (isForumCell()) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 86 : 91 + (useSeparator ? 1 : 0))); + } else { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? heightThreeLines : heightDefault) + (useSeparator ? 1 : 0) + (twoLinesForName ? AndroidUtilities.dp(20) : 0)); + } topClip = 0; bottomClip = getMeasuredHeight(); } @@ -729,9 +762,9 @@ public class DialogCell extends BaseCell { return Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(17), false); } + int thumbSize; public void buildLayout() { - int thumbSize; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { Theme.dialogs_namePaint[1].setTextSize(AndroidUtilities.dp(16)); Theme.dialogs_nameEncryptedPaint[1].setTextSize(AndroidUtilities.dp(16)); @@ -760,10 +793,11 @@ public class DialogCell extends BaseCell { CharSequence messageString = ""; CharSequence messageNameString = null; CharSequence printingString = null; - if (isDialogCell || isTopic) { + CharSequence buttonString = null; + if (!isForumCell() && (isDialogCell || isTopic)) { printingString = MessagesController.getInstance(currentAccount).getPrintingString(currentDialogId, getTopicId(), true); } - TextPaint currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; + currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; boolean checkMessage = true; drawNameLock = false; @@ -779,19 +813,21 @@ public class DialogCell extends BaseCell { boolean drawTime = true; printingStringType = -1; int printingStringReplaceIndex = -1; + if (!isForumCell()) { + buttonLayout = null; + } String messageFormat; - boolean hasNameInMessage; if (Build.VERSION.SDK_INT >= 18) { - if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) { + if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell()) { messageFormat = "%2$s: \u2068%1$s\u2069"; hasNameInMessage = true; } else { - messageFormat = "\u2068%s\u2069"; + messageFormat = "\u2068%1$s\u2069"; hasNameInMessage = false; } } else { - if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) { + if ((!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0) || isForumCell()) { messageFormat = "%2$s: %1$s"; hasNameInMessage = true; } else { @@ -834,7 +870,7 @@ public class DialogCell extends BaseCell { } } } else { - drawVerified = customDialog.verified; + drawVerified = !forbidVerified && customDialog.verified; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { if (!LocaleController.isRTL) { nameLeft = AndroidUtilities.dp(messagePaddingStart + 6); @@ -954,7 +990,7 @@ public class DialogCell extends BaseCell { drawScam = 2; Theme.dialogs_fakeDrawable.checkText(); } else { - drawVerified = chat.verified; + drawVerified = !forbidVerified && chat.verified; } } else if (user != null) { if (user.scam) { @@ -964,7 +1000,7 @@ public class DialogCell extends BaseCell { drawScam = 2; Theme.dialogs_fakeDrawable.checkText(); } else { - drawVerified = user.verified; + drawVerified =!forbidVerified && user.verified; } drawPremium = MessagesController.getInstance(currentAccount).isPremiumUser(user) && UserConfig.getInstance(currentAccount).clientUserId != user.id && user.id != 0; if (drawPremium) { @@ -1001,12 +1037,25 @@ public class DialogCell extends BaseCell { if (draftMessage != null && (TextUtils.isEmpty(draftMessage.message) && draftMessage.reply_to_msg_id == 0 || lastDate > draftMessage.date && unreadCount != 0) || ChatObject.isChannel(chat) && !chat.megagroup && !chat.creator && (chat.admin_rights == null || !chat.admin_rights.post_messages) || - chat != null && (chat.left || chat.kicked)) { + chat != null && (chat.left || chat.kicked) || forbidDraft || ChatObject.isForum(chat) && !isTopic) { draftMessage = null; } - - if (printingString != null) { + if (isForumCell()) { + draftMessage = null; + needEmoji = true; + updateMessageThumbs(); + messageNameString = getMessageNameString(); + messageString = formatTopicsNames(); + String restrictionReason = MessagesController.getRestrictionReason(message.messageOwner.restriction_reason); + buttonString = getMessageStringFormatted(messageFormat, restrictionReason, messageNameString, true); + if (applyName && buttonString.length() >= 0) { + SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf(buttonString); + spannableStringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_name, resourcesProvider), 0, Math.min(spannableStringBuilder.length(), messageNameString.length() + 1), 0); + buttonString = spannableStringBuilder; + } + currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; + } else if (printingString != null) { lastPrintString = printingString; printingStringType = MessagesController.getInstance(currentAccount).getPrintingStringType(currentDialogId, getTopicId()); StatusDrawable statusDrawable = Theme.getChatStatusDrawable(printingStringType); @@ -1169,78 +1218,10 @@ public class DialogCell extends BaseCell { } currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; } else { - boolean needEmoji = true; - if (groupMessages != null && groupMessages.size() > 1 && TextUtils.isEmpty(restrictionReason) && currentDialogFolderId == 0 && encryptedChat == null) { - thumbsCount = 0; - hasVideoThumb = false; - Collections.sort(groupMessages, (a, b) -> a.getId() - b.getId()); - for (int i = 0; i < groupMessages.size(); ++i) { - MessageObject message = groupMessages.get(i); - if (message != null && !message.needDrawBluredPreview() && (message.isPhoto() || message.isNewGif() || message.isVideo() || message.isRoundVideo())) { - String type = message.isWebpage() ? message.messageOwner.media.webpage.type : null; - if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { - TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 40); - TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (smallThumb == bigThumb) { - bigThumb = null; - } - if (smallThumb != null) { - hasVideoThumb = hasVideoThumb || (message.isVideo() || message.isRoundVideo()); - if (i < 2) { - thumbsCount++; - drawPlay[i] = message.isVideo() || message.isRoundVideo(); - int size = message.type == MessageObject.TYPE_PHOTO && bigThumb != null ? bigThumb.size : 0; - thumbImage[i].setImage(ImageLocation.getForObject(bigThumb, message.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", size, null, message, 0); - thumbImage[i].setRoundRadius(message.isRoundVideo() ? AndroidUtilities.dp(18) : AndroidUtilities.dp(2)); - needEmoji = false; - } - } - } - } - } - } else if (message != null && currentDialogFolderId == 0) { - thumbsCount = 0; - hasVideoThumb = false; - if (!message.needDrawBluredPreview() && (message.isPhoto() || message.isNewGif() || message.isVideo() || message.isRoundVideo())) { - String type = message.isWebpage() ? message.messageOwner.media.webpage.type : null; - if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { - TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 40); - TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (smallThumb == bigThumb) { - bigThumb = null; - } - if (smallThumb != null) { - hasVideoThumb = hasVideoThumb || (message.isVideo() || message.isRoundVideo()); - if (thumbsCount < 3) { - thumbsCount++; - drawPlay[0] = message.isVideo() || message.isRoundVideo(); - int size = message.type == MessageObject.TYPE_PHOTO && bigThumb != null ? bigThumb.size : 0; - thumbImage[0].setImage(ImageLocation.getForObject(bigThumb, message.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", size, null, message, 0); - thumbImage[0].setRoundRadius(message.isRoundVideo() ? AndroidUtilities.dp(18) : AndroidUtilities.dp(2)); - needEmoji = false; - } - } - } - } - } + needEmoji = true; + updateMessageThumbs(); if (chat != null && chat.id > 0 && fromChat == null && (!ChatObject.isChannel(chat) || ChatObject.isMegagroup(chat)) && !ForumUtilities.isTopicCreateMessage(message)) { - if (message.isOutOwner()) { - messageNameString = LocaleController.getString("FromYou", R.string.FromYou); - } else if (message != null && message.messageOwner.fwd_from != null && message.messageOwner.fwd_from.from_name != null) { - messageNameString = message.messageOwner.fwd_from.from_name; - } else if (fromUser != null) { - if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { - if (UserObject.isDeleted(fromUser)) { - messageNameString = LocaleController.getString("HiddenName", R.string.HiddenName); - } else { - messageNameString = ContactsController.formatName(fromUser.first_name, fromUser.last_name).replace("\n", ""); - } - } else { - messageNameString = UserObject.getFirstName(fromUser).replace("\n", ""); - } - } else { - messageNameString = "DELETED"; - } + messageNameString = getMessageNameString(); if (chat.forum && !isTopic) { CharSequence topicName = MessagesController.getInstance(currentAccount).getTopicsController().getTopicIconName(chat, message, currentMessagePaint); if (!TextUtils.isEmpty(topicName)) { @@ -1254,142 +1235,8 @@ public class DialogCell extends BaseCell { } } checkMessage = false; - SpannableStringBuilder stringBuilder; - MessageObject captionMessage = getCaptionMessage(); - if (!TextUtils.isEmpty(restrictionReason)) { - stringBuilder = SpannableStringBuilder.valueOf(String.format(messageFormat, restrictionReason, messageNameString)); - } else if (MessageObject.isTopicActionMessage(message)) { - CharSequence mess; - if (message.messageTextShort != null && (!(message.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate) || !isTopic)) { - mess = message.messageTextShort; - } else { - mess = message.messageText; - } - stringBuilder = AndroidUtilities.formatSpannable(messageFormat, mess, messageNameString); - if (message.topicIconDrawable[0] != null) { - TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(message.messageOwner)); - if (topic != null) { - message.topicIconDrawable[0].setColor(topic.icon_color); - } - } - } else if (captionMessage != null && captionMessage.caption != null) { - MessageObject message = captionMessage; - CharSequence mess = message.caption.toString(); - String emoji; - if (!needEmoji) { - emoji = ""; - } else if (message.isVideo()) { - emoji = "\uD83D\uDCF9 "; - } else if (message.isVoice()) { - emoji = "\uD83C\uDFA4 "; - } else if (message.isMusic()) { - emoji = "\uD83C\uDFA7 "; - } else if (message.isPhoto()) { - emoji = "\uD83D\uDDBC "; - } else { - emoji = "\uD83D\uDCCE "; - } - if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { - String str = message.messageTrimmedToHighlight; - if (message.messageTrimmedToHighlight != null) { - str = message.messageTrimmedToHighlight; - } - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 24); - if (hasNameInMessage) { - if (!TextUtils.isEmpty(messageNameString)) { - w -= currentMessagePaint.measureText(messageNameString.toString()); - } - w -= currentMessagePaint.measureText(": "); - } - if (w > 0) { - str = AndroidUtilities.ellipsizeCenterEnd(str, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); - } - stringBuilder = new SpannableStringBuilder(emoji).append(str); - } else { - if (mess.length() > 150) { - mess = mess.subSequence(0, 150); - } - SpannableStringBuilder msgBuilder = new SpannableStringBuilder(mess); - MediaDataController.addTextStyleRuns(message.messageOwner.entities, mess, msgBuilder, TextStyleSpan.FLAG_STYLE_SPOILER); - if (message != null && message.messageOwner != null) { - MediaDataController.addAnimatedEmojiSpans(message.messageOwner.entities, msgBuilder, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); - } - stringBuilder = AndroidUtilities.formatSpannable(messageFormat, new SpannableStringBuilder(emoji).append(AndroidUtilities.replaceNewLines(msgBuilder)), messageNameString); - } - } else if (message.messageOwner.media != null && !message.isMediaEmpty()) { - currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; - String innerMessage; - String colorKey = Theme.key_chats_attachMessage; - if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { - TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) message.messageOwner.media; - if (Build.VERSION.SDK_INT >= 18) { - innerMessage = String.format("\uD83D\uDCCA \u2068%s\u2069", mediaPoll.poll.question); - } else { - innerMessage = String.format("\uD83D\uDCCA %s", mediaPoll.poll.question); - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { - if (Build.VERSION.SDK_INT >= 18) { - innerMessage = String.format("\uD83C\uDFAE \u2068%s\u2069", message.messageOwner.media.game.title); - } else { - innerMessage = String.format("\uD83C\uDFAE %s", message.messageOwner.media.game.title); - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) { - innerMessage = message.messageOwner.media.title; - } else if (message.type == MessageObject.TYPE_MUSIC) { - if (Build.VERSION.SDK_INT >= 18) { - innerMessage = String.format("\uD83C\uDFA7 \u2068%s - %s\u2069", message.getMusicAuthor(), message.getMusicTitle()); - } else { - innerMessage = String.format("\uD83C\uDFA7 %s - %s", message.getMusicAuthor(), message.getMusicTitle()); - } - } else if (thumbsCount > 1) { - if (hasVideoThumb) { - innerMessage = LocaleController.formatPluralString("Media", groupMessages == null ? 0 : groupMessages.size()); - } else { - innerMessage = LocaleController.formatPluralString("Photos", groupMessages == null ? 0 : groupMessages.size()); - } - colorKey = Theme.key_chats_actionMessage; - } else { - innerMessage = msgText.toString(); - colorKey = Theme.key_chats_actionMessage; - } - innerMessage = innerMessage.replace('\n', ' '); - stringBuilder = AndroidUtilities.formatSpannable(messageFormat, innerMessage, messageNameString); - try { - stringBuilder.setSpan(new ForegroundColorSpanThemable(colorKey, resourcesProvider), hasNameInMessage ? messageNameString.length() + 2 : 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } catch (Exception e) { - FileLog.e(e); - } - } else if (message.messageOwner.message != null) { - CharSequence mess = message.messageOwner.message; - if (message.hasHighlightedWords()) { - if (message.messageTrimmedToHighlight != null) { - mess = message.messageTrimmedToHighlight; - } - int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 10); - if (hasNameInMessage) { - if (!TextUtils.isEmpty(messageNameString)) { - w -= currentMessagePaint.measureText(messageNameString.toString()); - } - w -= currentMessagePaint.measureText(": "); - } - if (w > 0) { - mess = AndroidUtilities.ellipsizeCenterEnd(mess, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); - } - } else { - if (mess.length() > 150) { - mess = mess.subSequence(0, 150); - } - mess = AndroidUtilities.replaceNewLines(mess); - } - mess = new SpannableStringBuilder(mess); - MediaDataController.addTextStyleRuns(message, (Spannable) mess, TextStyleSpan.FLAG_STYLE_SPOILER); - if (message != null && message.messageOwner != null) { - MediaDataController.addAnimatedEmojiSpans(message.messageOwner.entities, mess, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); - } - stringBuilder = AndroidUtilities.formatSpannable(messageFormat, mess, messageNameString); - } else { - stringBuilder = SpannableStringBuilder.valueOf(""); - } + SpannableStringBuilder stringBuilder = getMessageStringFormatted(messageFormat, restrictionReason, messageNameString, false); + int thumbInsertIndex = 0; if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0 && stringBuilder.length() > 0) { try { @@ -1994,7 +1841,17 @@ public class DialogCell extends BaseCell { } } messageWidth = Math.max(AndroidUtilities.dp(12), messageWidth); - if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && messageNameString != null && (currentDialogFolderId == 0 || currentDialogFolderDialogsCount == 1)) { + buttonTop = useForceThreeLines || SharedConfig.useThreeLinesLayout ? AndroidUtilities.dp(58) : AndroidUtilities.dp(62); + if (isForumCell()) { + if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { + messageTop = AndroidUtilities.dp(34); + } else { + messageTop = AndroidUtilities.dp(39); + } + for (int i = 0; i < thumbImage.length; ++i) { + thumbImage[i].setImageY(buttonTop); + } + } else if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && messageNameString != null && (currentDialogFolderId == 0 || currentDialogFolderDialogsCount == 1)) { try { if (message != null && message.hasHighlightedWords()) { CharSequence s = AndroidUtilities.highlightText(messageNameString, message.highlightedWords, resourcesProvider); @@ -2023,11 +1880,30 @@ public class DialogCell extends BaseCell { messageTop = AndroidUtilities.dp(39); } } + if (twoLinesForName) { messageTop += AndroidUtilities.dp(20); } animatedEmojiStack2 = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack2, messageNameLayout); + + try { + if (!TextUtils.isEmpty(buttonString)) { + buttonString = Emoji.replaceEmoji(buttonString, currentMessagePaint.getFontMetricsInt(), AndroidUtilities.dp(17), false); + CharSequence buttonStringFinal = TextUtils.ellipsize(buttonString, currentMessagePaint, messageWidth - AndroidUtilities.dp(26), TextUtils.TruncateAt.END); + buttonLayout = new StaticLayout(buttonStringFinal, currentMessagePaint, messageWidth - AndroidUtilities.dp(20), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + spoilersPool2.addAll(spoilers2); + spoilers2.clear(); + SpoilerEffect.addSpoilers(this, buttonLayout, spoilersPool2, spoilers2); + } else { + buttonLayout = null; + } + } catch (Exception e) { + + } + animatedEmojiStack3 = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack3, buttonLayout); + try { CharSequence messageStringFinal; if ((useForceThreeLines || SharedConfig.useThreeLinesLayout) && currentDialogFolderId != 0 && currentDialogFolderDialogsCount > 1) { @@ -2035,9 +1911,10 @@ public class DialogCell extends BaseCell { messageNameString = null; currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; } else if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || messageNameString != null) { - messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); - if (messageStringFinal instanceof Spanned && ((Spanned) messageStringFinal).getSpans(0, messageStringFinal.length(), FixedWidthSpan.class).length <= 0) { + if (!isForumCell() && messageString instanceof Spanned && ((Spanned) messageString).getSpans(0, messageString.length(), FixedWidthSpan.class).length <= 0) { messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12 + (thumbsCount * (thumbSize + 2) - 2) + 5), TextUtils.TruncateAt.END); + } else { + messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); } } else { messageStringFinal = messageString; @@ -2069,11 +1946,11 @@ public class DialogCell extends BaseCell { spoilersPool.addAll(spoilers); spoilers.clear(); SpoilerEffect.addSpoilers(this, messageLayout, spoilersPool, spoilers); - animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack, messageLayout); } catch (Exception e) { messageLayout = null; FileLog.e(e); } + animatedEmojiStack = AnimatedEmojiSpan.update(AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, this, animatedEmojiStack, messageLayout); double widthpx; float left; @@ -2163,25 +2040,6 @@ public class DialogCell extends BaseCell { messageNameLeft -= messageNameLayout.getLineLeft(0); } } - if (messageLayout != null && thumbsCount > 0) { - try { - int textLen = messageLayout.getText().length(); - if (offsetName >= textLen) { - offsetName = textLen - 1; - } - float x1 = messageLayout.getPrimaryHorizontal(offsetName); - float x2 = messageLayout.getPrimaryHorizontal(offsetName + 1); - int offset = (int) Math.ceil(Math.min(x1, x2)); - if (offset != 0) { - offset += AndroidUtilities.dp(3); - } - for (int i = 0; i < thumbsCount; ++i) { - thumbImage[i].setImageX(messageLeft + offset + AndroidUtilities.dp((thumbSize + 2) * i)); - } - } catch (Exception e) { - FileLog.e(e); - } - } if (messageLayout != null && printingStringType >= 0 && messageLayout.getText().length() > 0) { float x1, x2; if (printingStringReplaceIndex >= 0 && printingStringReplaceIndex + 1 < messageLayout.getText().length() ){ @@ -2197,6 +2055,132 @@ public class DialogCell extends BaseCell { statusDrawableLeft = (int) (messageLeft + x2 + AndroidUtilities.dp(3)); } } + updateThumbsPosition(); + } + + private void updateThumbsPosition() { + if (thumbsCount > 0) { + StaticLayout layout = isForumCell() ? buttonLayout : messageLayout; + if (layout == null) { + return; + } + try { + CharSequence text = layout.getText(); + if (text instanceof Spannable) { + FixedWidthSpan[] spans = ((Spannable) text).getSpans(0, text.length(), FixedWidthSpan.class); + if (spans != null && spans.length > 0) { + int spanOffset = ((Spannable) text).getSpanStart(spans[0]); + if (spanOffset < 0) { + spanOffset = 0; + } + + float x1 = layout.getPrimaryHorizontal(spanOffset); + float x2 = layout.getPrimaryHorizontal(spanOffset + 1); + int offset = (int) Math.ceil(Math.min(x1, x2)); + if (offset != 0) { + offset += AndroidUtilities.dp(3); + } + for (int i = 0; i < thumbsCount; ++i) { + thumbImage[i].setImageX(messageLeft + offset + AndroidUtilities.dp((thumbSize + 2) * i)); + } + } + } + } catch (Exception e) { + FileLog.e(e); + } + } + } + + private CharSequence applyThumbs(CharSequence string) { + if (thumbsCount > 0) { + SpannableStringBuilder builder = SpannableStringBuilder.valueOf(string); + builder.insert(0, " "); + builder.setSpan(new FixedWidthSpan(AndroidUtilities.dp((thumbSize + 2) * thumbsCount - 2 + 5)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return builder; + } + return string; + } + + int topMessageTopicStartIndex; + int topMessageTopicEndIndex; + + private CharSequence formatTopicsNames() { + topMessageTopicStartIndex = 0; + topMessageTopicEndIndex = 0; + if (chat != null) { + List topics = MessagesController.getInstance(currentAccount).getTopicsController().getTopics(chat.id); + + boolean hasDivider = false; + if (topics != null && !topics.isEmpty()) { + topics = new ArrayList<>(topics); + Collections.sort(topics, Comparator.comparingInt(o -> -o.top_message)); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + int topMessageTopicId = 0; + int boldLen = 0; + if (message != null) { + topMessageTopicId = MessageObject.getTopicId(message.messageOwner); + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(chat.id, topMessageTopicId); + if (topic != null) { + CharSequence topicString = ForumUtilities.getTopicSpannedName(topic, currentMessagePaint); + spannableStringBuilder.append(topicString); + if (topic.unread_count > 0) { + boldLen = topicString.length(); + } + topMessageTopicStartIndex = 0; + topMessageTopicEndIndex = topicString.length(); + + if (message.isOutOwner()) { + lastTopicMessageUnread = topic.read_inbox_max_id < message.getId(); + } else { + lastTopicMessageUnread = topic.unread_count > 0; + } + } + if (lastTopicMessageUnread) { + spannableStringBuilder.append(" "); + spannableStringBuilder.setSpan(new FixedWidthSpan(AndroidUtilities.dp(3)), spannableStringBuilder.length() - 1, spannableStringBuilder.length(), 0); + hasDivider = true; + } + } + + boolean firstApplay = true; + for (int i = 0; i < Math.min(5, topics.size()); i++) { + if (topics.get(i).id == topMessageTopicId) { + continue; + } + + if (spannableStringBuilder.length() != 0) { + if (firstApplay && hasDivider) { + spannableStringBuilder.append(" "); + } else { + spannableStringBuilder.append(", "); + } + } + firstApplay = false; + CharSequence topicString = ForumUtilities.getTopicSpannedName(topics.get(i), currentMessagePaint); + spannableStringBuilder.append(topicString); + } + if (boldLen > 0) { + spannableStringBuilder.setSpan( + new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, Theme.getColor(Theme.key_chats_name, resourcesProvider)), + 0, Math.min(spannableStringBuilder.length(), boldLen + 2), 0 + ); + } + return spannableStringBuilder; + } + + if (!MessagesController.getInstance(currentAccount).getTopicsController().endIsReached(chat.id)) { + MessagesController.getInstance(currentAccount).getTopicsController().preloadTopics(chat.id); + return "Loading..."; + } else { + return "no created topics"; + } + } + + return null; + } + + protected boolean isForumCell() { + return !isDialogFolder() && chat != null && chat.forum && !isTopic; } private void drawCheckStatus(Canvas canvas, boolean drawClock, boolean drawCheck1, boolean drawCheck2, boolean moveCheck, float alpha) { @@ -2282,11 +2266,12 @@ public class DialogCell extends BaseCell { isSelected = value; } - public void checkCurrentDialogIndex(boolean frozen) { + public boolean checkCurrentDialogIndex(boolean frozen) { if (parentFragment == null) { - return; + return false; } ArrayList dialogsArray = parentFragment.getDialogsArray(currentAccount, dialogsType, folderId, frozen); + boolean requestLayout = false; if (index < dialogsArray.size()) { TLRPC.Dialog dialog = dialogsArray.get(index); TLRPC.Dialog nextDialog = index + 1 < dialogsArray.size() ? dialogsArray.get(index + 1) : null; @@ -2309,6 +2294,11 @@ public class DialogCell extends BaseCell { newDraftMessage != draftMessage || drawPin != dialog.pinned) { boolean dialogChanged = currentDialogId != dialog.id; + if (isForum != MessagesController.getInstance(currentAccount).isForum(dialog.id)) { + requestLayout = true; + } + isForum = MessagesController.getInstance(currentAccount).isForum(dialog.id); + currentDialogId = dialog.id; if (dialogChanged) { lastDialogChangedTime = System.currentTimeMillis(); @@ -2342,6 +2332,10 @@ public class DialogCell extends BaseCell { checkChatTheme(); } } + if (requestLayout) { + requestLayout(); + } + return requestLayout; } public void animateArchiveAvatar() { @@ -2392,11 +2386,12 @@ public class DialogCell extends BaseCell { return currentDialogFolderId != 0; } - public void update(int mask) { - update(mask, true); + public boolean update(int mask) { + return update(mask, true); } - public void update(int mask, boolean animated) { + public boolean update(int mask, boolean animated) { + boolean requestLayout = false; if (customDialog != null) { lastMessageDate = customDialog.date; lastUnreadState = customDialog.unread_count != 0; @@ -2415,6 +2410,7 @@ public class DialogCell extends BaseCell { int oldUnreadCount = unreadCount; boolean oldHasReactionsMentions = reactionMentionCount != 0; boolean oldMarkUnread = markUnread; + boolean oldIsForumCell = isForumCell(); hasUnmutedTopics = false; readOutboxMaxId = -1; if (isDialogCell) { @@ -2427,6 +2423,10 @@ public class DialogCell extends BaseCell { message = groupMessages != null && groupMessages.size() > 0 ? groupMessages.get(0) : null; lastUnreadState = message != null && message.isUnread(); TLRPC.Chat localChat = MessagesController.getInstance(currentAccount).getChat(-dialog.id); + boolean isForumCell = localChat != null && localChat.forum && !isTopic; + if (isForumCell != oldIsForumCell) { + requestLayout = true; + } if (localChat != null && localChat.forum) { int[] counts = MessagesController.getInstance(currentAccount).getTopicsController().getForumUnreadCount(localChat.id); unreadCount = counts[0]; @@ -2581,7 +2581,7 @@ public class DialogCell extends BaseCell { if (!continueUpdate) { invalidate(); - return; + return requestLayout; } } @@ -2751,7 +2751,7 @@ public class DialogCell extends BaseCell { reactionsMentionsAnimator.start(); } - avatarImage.setRoundRadius(isDialogCell && chat != null && chat.forum && currentDialogFolderId == 0 ? AndroidUtilities.dp(16) : AndroidUtilities.dp(28)); + avatarImage.setRoundRadius(chat != null && chat.forum && currentDialogFolderId == 0 ? AndroidUtilities.dp(16) : AndroidUtilities.dp(28)); } if (!isTopic && (getMeasuredWidth() != 0 || getMeasuredHeight() != 0)) { buildLayout(); @@ -2767,6 +2767,7 @@ public class DialogCell extends BaseCell { } invalidate(); + return requestLayout; } private int getTopicId() { @@ -3128,7 +3129,7 @@ public class DialogCell extends BaseCell { Theme.dialogs_lock2Drawable.draw(canvas); } - if (messageNameLayout != null) { + if (messageNameLayout != null && !isForumCell()) { if (currentDialogFolderId != 0) { Theme.dialogs_messageNamePaint.setColor(Theme.dialogs_messageNamePaint.linkColor = Theme.getColor(Theme.key_chats_nameMessageArchived_threeLines, resourcesProvider)); } else if (draftMessage != null) { @@ -3197,6 +3198,67 @@ public class DialogCell extends BaseCell { } } + if (buttonLayout != null) { + canvas.save(); + if (buttonBackgroundPaint == null) { + buttonBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + if (canvasButton == null) { + canvasButton = new CanvasButton(this); + canvasButton.setDelegate(() -> { + delegate.onButtonClicked(this); + }); + canvasButton.setLongPress(() -> { + delegate.onButtonLongPress(this); + }); + } + + if (lastTopicMessageUnread) { + canvasButton.setColor(ColorUtils.setAlphaComponent(currentMessagePaint.getColor(), Theme.isCurrentThemeDark() ? 36 : 26)); + canvasButton.rewind(); + if (topMessageTopicEndIndex != topMessageTopicStartIndex && topMessageTopicEndIndex > 0) { + AndroidUtilities.rectTmp.set(messageLeft + AndroidUtilities.dp(2), messageTop, messageLeft + messageLayout.getPrimaryHorizontal(Math.min(messageLayout.getText().length(), topMessageTopicEndIndex)) - AndroidUtilities.dp(3), buttonTop - AndroidUtilities.dp(4)); + AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(4)); + if (AndroidUtilities.rectTmp.right > AndroidUtilities.rectTmp.left) { + canvasButton.addRect(AndroidUtilities.rectTmp); + } + } + + AndroidUtilities.rectTmp.set(messageLeft + AndroidUtilities.dp(2), buttonTop + AndroidUtilities.dp(2), messageLeft + buttonLayout.getLineWidth(0) + AndroidUtilities.dp(12), buttonTop + buttonLayout.getHeight()); + AndroidUtilities.rectTmp.inset(-AndroidUtilities.dp(8), -AndroidUtilities.dp(3)); + canvasButton.addRect(AndroidUtilities.rectTmp); + canvasButton.draw(canvas); + + Theme.dialogs_forum_arrowDrawable.setAlpha(125); + setDrawableBounds(Theme.dialogs_forum_arrowDrawable, AndroidUtilities.rectTmp.right - AndroidUtilities.dp(18), AndroidUtilities.rectTmp.top + (AndroidUtilities.rectTmp.height() - Theme.dialogs_forum_arrowDrawable.getIntrinsicHeight()) / 2f); + Theme.dialogs_forum_arrowDrawable.draw(canvas); + } + + + canvas.translate(messageLeft - buttonLayout.getLineLeft(0), buttonTop); + if (!spoilers2.isEmpty()) { + try { + canvas.save(); + SpoilerEffect.clipOutCanvas(canvas, spoilers2); + buttonLayout.draw(canvas); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, spoilers2, 0, 0, 0, 1f); + canvas.restore(); + + for (int i = 0; i < spoilers2.size(); i++) { + SpoilerEffect eff = spoilers2.get(i); + eff.setColor(buttonLayout.getPaint().getColor()); + eff.draw(canvas); + } + } catch (Exception e) { + FileLog.e(e); + } + } else { + buttonLayout.draw(canvas); + AnimatedEmojiSpan.drawAnimatedEmojis(canvas, buttonLayout, animatedEmojiStack3, -.075f, null, 0, 0, 0, 1f); + } + canvas.restore(); + } + if (currentDialogFolderId == 0) { int currentStatus = (drawClock ? 1 : 0) + (drawCheck1 ? 2 : 0) + (drawCheck2 ? 4 : 0); @@ -3314,10 +3376,26 @@ public class DialogCell extends BaseCell { } if (drawCount && drawCount2 || countChangeProgress != 1f) { final float progressFinal = (unreadCount == 0 && !markUnread) ? 1f - countChangeProgress : countChangeProgress; + Paint paint; + int fillPaintAlpha = 255; + boolean restoreCountTextPaint = false; + if (isTopic && forumTopic.read_inbox_max_id == 0) { + if (topicCounterPaint == null) { + topicCounterPaint = new Paint(); + } + paint = topicCounterPaint; + int color = Theme.getColor(drawCounterMuted ? Theme.key_topics_unreadCounterMuted : Theme.key_topics_unreadCounter, resourcesProvider); + paint.setColor(color); + Theme.dialogs_countTextPaint.setColor(color); + fillPaintAlpha = drawCounterMuted ? 30 : 40; + restoreCountTextPaint = true; + } else { + paint = drawCounterMuted || currentDialogFolderId != 0 ? Theme.dialogs_countGrayPaint : Theme.dialogs_countPaint; + } + if (countOldLayout == null || unreadCount == 0) { StaticLayout drawLayout = unreadCount == 0 ? countOldLayout : countLayout; - Paint paint = drawCounterMuted || currentDialogFolderId != 0 ? Theme.dialogs_countGrayPaint : Theme.dialogs_countPaint; - paint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); + paint.setAlpha((int) ((1.0f - reorderIconProgress) * fillPaintAlpha)); Theme.dialogs_countTextPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); int x = countLeft - AndroidUtilities.dp(5.5f); @@ -3348,8 +3426,7 @@ public class DialogCell extends BaseCell { canvas.restore(); } } else { - Paint paint = drawCounterMuted || currentDialogFolderId != 0 ? Theme.dialogs_countGrayPaint : Theme.dialogs_countPaint; - paint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); + paint.setAlpha((int) ((1.0f - reorderIconProgress) * fillPaintAlpha)); Theme.dialogs_countTextPaint.setAlpha((int) ((1.0f - reorderIconProgress) * 255)); float progressHalf = progressFinal * 2; @@ -3403,7 +3480,9 @@ public class DialogCell extends BaseCell { } Theme.dialogs_countTextPaint.setAlpha(textAlpha); canvas.restore(); - + } + if (restoreCountTextPaint) { + Theme.dialogs_countTextPaint.setColor(Theme.getColor(Theme.key_chats_unreadCounterText)); } } if (drawMention) { @@ -3954,6 +4033,274 @@ public class DialogCell extends BaseCell { return captionMessage; } + public void updateMessageThumbs() { + if (message == null) { + return; + } + String restrictionReason = MessagesController.getRestrictionReason(message.messageOwner.restriction_reason); + if (groupMessages != null && groupMessages.size() > 1 && TextUtils.isEmpty(restrictionReason) && currentDialogFolderId == 0 && encryptedChat == null) { + thumbsCount = 0; + hasVideoThumb = false; + Collections.sort(groupMessages, (a, b) -> a.getId() - b.getId()); + for (int i = 0; i < groupMessages.size(); ++i) { + MessageObject message = groupMessages.get(i); + if (message != null && !message.needDrawBluredPreview() && (message.isPhoto() || message.isNewGif() || message.isVideo() || message.isRoundVideo())) { + String type = message.isWebpage() ? message.messageOwner.media.webpage.type : null; + if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { + TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 40); + TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); + if (smallThumb == bigThumb) { + bigThumb = null; + } + if (smallThumb != null) { + hasVideoThumb = hasVideoThumb || (message.isVideo() || message.isRoundVideo()); + if (i < 2) { + thumbsCount++; + drawPlay[i] = message.isVideo() || message.isRoundVideo(); + int size = message.type == MessageObject.TYPE_PHOTO && bigThumb != null ? bigThumb.size : 0; + thumbImage[i].setImage(ImageLocation.getForObject(bigThumb, message.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", size, null, message, 0); + thumbImage[i].setRoundRadius(message.isRoundVideo() ? AndroidUtilities.dp(18) : AndroidUtilities.dp(2)); + needEmoji = false; + } + } + } + } + } + } else if (message != null && currentDialogFolderId == 0) { + thumbsCount = 0; + hasVideoThumb = false; + if (!message.needDrawBluredPreview() && (message.isPhoto() || message.isNewGif() || message.isVideo() || message.isRoundVideo())) { + String type = message.isWebpage() ? message.messageOwner.media.webpage.type : null; + if (!("app".equals(type) || "profile".equals(type) || "article".equals(type) || type != null && type.startsWith("telegram_"))) { + TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 40); + TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); + if (smallThumb == bigThumb) { + bigThumb = null; + } + if (smallThumb != null) { + hasVideoThumb = hasVideoThumb || (message.isVideo() || message.isRoundVideo()); + if (thumbsCount < 3) { + thumbsCount++; + drawPlay[0] = message.isVideo() || message.isRoundVideo(); + int size = message.type == MessageObject.TYPE_PHOTO && bigThumb != null ? bigThumb.size : 0; + thumbImage[0].setImage(ImageLocation.getForObject(bigThumb, message.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, message.photoThumbsObject), "20_20", size, null, message, 0); + thumbImage[0].setRoundRadius(message.isRoundVideo() ? AndroidUtilities.dp(18) : AndroidUtilities.dp(2)); + needEmoji = false; + } + } + } + } + } + } + + public String getMessageNameString() { + if (message == null) { + return null; + } + TLRPC.User user; + TLRPC.User fromUser = null; + TLRPC.Chat fromChat = null; + long fromId = message.getFromChatId(); + if (DialogObject.isUserDialog(fromId)) { + fromUser = MessagesController.getInstance(currentAccount).getUser(fromId); + } else { + fromChat = MessagesController.getInstance(currentAccount).getChat(-fromId); + } + + if (message.isOutOwner()) { + return LocaleController.getString("FromYou", R.string.FromYou); + } else if (message != null && message.messageOwner != null && message.messageOwner.from_id instanceof TLRPC.TL_peerUser && (user = MessagesController.getInstance(currentAccount).getUser(message.messageOwner.from_id.user_id)) != null) { + return UserObject.getFirstName(user).replace("\n", ""); + } else if (message != null && message.messageOwner != null && message.messageOwner.fwd_from != null && message.messageOwner.fwd_from.from_name != null) { + return message.messageOwner.fwd_from.from_name; + } else if (fromUser != null) { + if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { + if (UserObject.isDeleted(fromUser)) { + return LocaleController.getString("HiddenName", R.string.HiddenName); + } else { + return ContactsController.formatName(fromUser.first_name, fromUser.last_name).replace("\n", ""); + } + } else { + return UserObject.getFirstName(fromUser).replace("\n", ""); + } + } else if (fromChat != null && fromChat.title != null) { + return fromChat.title.replace("\n", ""); + }else { + return "DELETED"; + } + } + + public SpannableStringBuilder getMessageStringFormatted(String messageFormat, String restrictionReason, CharSequence messageNameString, boolean applyThumbs) { + SpannableStringBuilder stringBuilder; + MessageObject captionMessage = getCaptionMessage(); + CharSequence msgText = message != null ? message.messageText : null; + applyName = true; + if (!TextUtils.isEmpty(restrictionReason)) { + stringBuilder = SpannableStringBuilder.valueOf(AndroidUtilities.formatSpannable(messageFormat, restrictionReason, messageNameString)); + } else if (message.messageOwner instanceof TLRPC.TL_messageService) { + CharSequence mess; + if (message.messageTextShort != null && (!(message.messageOwner.action instanceof TLRPC.TL_messageActionTopicCreate) || !isTopic)) { + mess = message.messageTextShort; + } else { + mess = message.messageText; + } + if (MessageObject.isTopicActionMessage(message)) { + stringBuilder = AndroidUtilities.formatSpannable(messageFormat, mess, messageNameString); + if (message.topicIconDrawable[0] != null) { + TLRPC.TL_forumTopic topic = MessagesController.getInstance(currentAccount).getTopicsController().findTopic(-message.getDialogId(), MessageObject.getTopicId(message.messageOwner)); + if (topic != null) { + message.topicIconDrawable[0].setColor(topic.icon_color); + } + } + } else { + applyName = false; + stringBuilder = SpannableStringBuilder.valueOf(mess); + } + } else if (captionMessage != null && captionMessage.caption != null) { + MessageObject message = captionMessage; + CharSequence mess = message.caption.toString(); + String emoji; + if (!needEmoji) { + emoji = ""; + } else if (message.isVideo()) { + emoji = "\uD83D\uDCF9 "; + } else if (message.isVoice()) { + emoji = "\uD83C\uDFA4 "; + } else if (message.isMusic()) { + emoji = "\uD83C\uDFA7 "; + } else if (message.isPhoto()) { + emoji = "\uD83D\uDDBC "; + } else { + emoji = "\uD83D\uDCCE "; + } + if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { + String str = message.messageTrimmedToHighlight; + if (message.messageTrimmedToHighlight != null) { + str = message.messageTrimmedToHighlight; + } + int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 24); + if (hasNameInMessage) { + if (!TextUtils.isEmpty(messageNameString)) { + w -= currentMessagePaint.measureText(messageNameString.toString()); + } + w -= currentMessagePaint.measureText(": "); + } + if (w > 0) { + str = AndroidUtilities.ellipsizeCenterEnd(str, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); + } + stringBuilder = new SpannableStringBuilder(emoji).append(str); + } else { + if (mess.length() > 150) { + mess = mess.subSequence(0, 150); + } + SpannableStringBuilder msgBuilder = new SpannableStringBuilder(mess); + MediaDataController.addTextStyleRuns(message.messageOwner.entities, mess, msgBuilder, TextStyleSpan.FLAG_STYLE_SPOILER); + if (message != null && message.messageOwner != null) { + MediaDataController.addAnimatedEmojiSpans(message.messageOwner.entities, msgBuilder, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); + } + CharSequence charSequence = new SpannableStringBuilder(emoji).append(AndroidUtilities.replaceNewLines(msgBuilder)); + if (applyThumbs) { + charSequence = applyThumbs(charSequence); + } + stringBuilder = AndroidUtilities.formatSpannable(messageFormat, charSequence, messageNameString); + } + } else if (message.messageOwner.media != null && !message.isMediaEmpty()) { + currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; + String innerMessage; + String colorKey = Theme.key_chats_attachMessage; + if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { + TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) message.messageOwner.media; + if (Build.VERSION.SDK_INT >= 18) { + innerMessage = String.format("\uD83D\uDCCA \u2068%s\u2069", mediaPoll.poll.question); + } else { + innerMessage = String.format("\uD83D\uDCCA %s", mediaPoll.poll.question); + } + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { + if (Build.VERSION.SDK_INT >= 18) { + innerMessage = String.format("\uD83C\uDFAE \u2068%s\u2069", message.messageOwner.media.game.title); + } else { + innerMessage = String.format("\uD83C\uDFAE %s", message.messageOwner.media.game.title); + } + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) { + innerMessage = message.messageOwner.media.title; + } else if (message.type == MessageObject.TYPE_MUSIC) { + if (Build.VERSION.SDK_INT >= 18) { + innerMessage = String.format("\uD83C\uDFA7 \u2068%s - %s\u2069", message.getMusicAuthor(), message.getMusicTitle()); + } else { + innerMessage = String.format("\uD83C\uDFA7 %s - %s", message.getMusicAuthor(), message.getMusicTitle()); + } + } else if (thumbsCount > 1) { + if (hasVideoThumb) { + innerMessage = LocaleController.formatPluralString("Media", groupMessages == null ? 0 : groupMessages.size()); + } else { + innerMessage = LocaleController.formatPluralString("Photos", groupMessages == null ? 0 : groupMessages.size()); + } + colorKey = Theme.key_chats_actionMessage; + } else { + innerMessage = msgText.toString(); + colorKey = Theme.key_chats_actionMessage; + } + innerMessage = innerMessage.replace('\n', ' '); + CharSequence message = innerMessage; + if (applyThumbs) { + message = applyThumbs(innerMessage); + } + stringBuilder = AndroidUtilities.formatSpannable(messageFormat, message, messageNameString); + if (!isForumCell()) { + try { + stringBuilder.setSpan(new ForegroundColorSpanThemable(colorKey, resourcesProvider), hasNameInMessage ? messageNameString.length() + 2 : 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } catch (Exception e) { + FileLog.e(e); + } + } + } else if (message.messageOwner.message != null) { + CharSequence mess = message.messageOwner.message; + if (message.hasHighlightedWords()) { + if (message.messageTrimmedToHighlight != null) { + mess = message.messageTrimmedToHighlight; + } + int w = getMeasuredWidth() - AndroidUtilities.dp(messagePaddingStart + 23 + 10); + if (hasNameInMessage) { + if (!TextUtils.isEmpty(messageNameString)) { + w -= currentMessagePaint.measureText(messageNameString.toString()); + } + w -= currentMessagePaint.measureText(": "); + } + if (w > 0) { + mess = AndroidUtilities.ellipsizeCenterEnd(mess, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); + } + } else { + if (mess.length() > 150) { + mess = mess.subSequence(0, 150); + } + mess = AndroidUtilities.replaceNewLines(mess); + } + mess = new SpannableStringBuilder(mess); + MediaDataController.addTextStyleRuns(message, (Spannable) mess, TextStyleSpan.FLAG_STYLE_SPOILER); + if (message != null && message.messageOwner != null) { + MediaDataController.addAnimatedEmojiSpans(message.messageOwner.entities, mess, currentMessagePaint == null ? null : currentMessagePaint.getFontMetricsInt()); + } + if (applyThumbs) { + mess = applyThumbs(mess); + } + stringBuilder = AndroidUtilities.formatSpannable(messageFormat, mess, messageNameString); + } else { + stringBuilder = SpannableStringBuilder.valueOf(""); + } + return stringBuilder; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (delegate == null || delegate.canClickButtonInside()) { + if (lastTopicMessageUnread && canvasButton != null && buttonLayout != null && canvasButton.checkTouchEvent(event)) { + return true; + } + } + return super.onTouchEvent(event); + } + + public void setClipProgress(float value) { clipProgress = value; invalidate(); @@ -3986,4 +4333,15 @@ public class DialogCell extends BaseCell { public MessageObject getMessage() { return message; } + + public void setDialogCellDelegate(DialogCellDelegate delegate) { + this.delegate = delegate; + } + + public interface DialogCellDelegate { + void onButtonClicked(DialogCell dialogCell); + void onButtonLongPress(DialogCell dialogCell); + boolean canClickButtonInside(); + } + } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java index 6984e7921..9b6031960 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeUsernameActivity.java @@ -61,6 +61,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -80,7 +81,9 @@ import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TypefaceSpan; import java.util.ArrayList; import java.util.List; @@ -585,19 +588,19 @@ public class ChangeUsernameActivity extends BaseFragment { } private UsernameHelpCell helpCell; - private TextView statusTextView; + private LinkSpanDrawable.LinksTextView statusTextView; private class UsernameHelpCell extends FrameLayout { private TextView text1View; - private TextView text2View; + private LinkSpanDrawable.LinksTextView text2View; public UsernameHelpCell(Context context) { super(context); helpCell = this; - setPadding(AndroidUtilities.dp(21), AndroidUtilities.dp(10), AndroidUtilities.dp(21), AndroidUtilities.dp(17)); + setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(10), AndroidUtilities.dp(18), AndroidUtilities.dp(17)); setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); setClipChildren(false); @@ -607,13 +610,50 @@ public class ChangeUsernameActivity extends BaseFragment { text1View.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); text1View.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText)); text1View.setHighlightColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection)); + text1View.setPadding(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(3), 0); - text2View = statusTextView = new TextView(context); + text2View = statusTextView = new LinkSpanDrawable.LinksTextView(context) { + @Override + public void setText(CharSequence text, BufferType type) { + if (text != null) { + SpannableStringBuilder tagsString = AndroidUtilities.replaceTags(text.toString()); + int index = tagsString.toString().indexOf('\n'); + if (index >= 0) { + tagsString.replace(index, index + 1, " "); + tagsString.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_windowBackgroundWhiteRedText4)), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + TypefaceSpan[] spans = tagsString.getSpans(0, tagsString.length(), TypefaceSpan.class); + for (int i = 0; i < spans.length; ++i) { + tagsString.setSpan( + new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + Browser.openUrl(getContext(), "https://fragment.com/username/" + username); + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }, + tagsString.getSpanStart(spans[i]), + tagsString.getSpanEnd(spans[i]), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + tagsString.removeSpan(spans[i]); + } + text = tagsString; + } + super.setText(text, type); + } + }; text2View.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); text2View.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText8)); text2View.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); text2View.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText)); text2View.setHighlightColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection)); + text2View.setPadding(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(3), 0); addView(text1View, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); addView(text2View, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP)); @@ -1120,7 +1160,7 @@ public class ChangeUsernameActivity extends BaseFragment { } } } - if (name == null || name.length() < 5) { + if (name == null || name.length() < 4) { if (alert) { AlertsCreator.showSimpleAlert(this, LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); } else { @@ -1196,9 +1236,23 @@ public class ChangeUsernameActivity extends BaseFragment { lastNameAvailable = true; } else { if (statusTextView != null) { - statusTextView.setText(LocaleController.getString("UsernameInUse", R.string.UsernameInUse)); - statusTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); - statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + if (error != null && "USERNAME_INVALID".equals(error.text) && req.username.length() == 4) { + statusTextView.setText(LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); + statusTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); + statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } else if (error != null && "USERNAME_PURCHASE_AVAILABLE".equals(error.text)) { + if (req.username.length() == 4) { + statusTextView.setText(LocaleController.getString("UsernameInvalidShortPurchase", R.string.UsernameInvalidShortPurchase)); + } else { + statusTextView.setText(LocaleController.getString("UsernameInUsePurchase", R.string.UsernameInUsePurchase)); + } + statusTextView.setTag(Theme.key_windowBackgroundWhiteGrayText8); + statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText8)); + } else { + statusTextView.setText(LocaleController.getString("UsernameInUse", R.string.UsernameInUse)); + statusTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); + statusTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } if (helpCell != null) { helpCell.update(); } @@ -1265,6 +1319,15 @@ public class ChangeUsernameActivity extends BaseFragment { } finishFragment(); }); + } else if ("USERNAME_PURCHASE_AVAILABLE".equals(error.text) || "USERNAME_INVALID".equals(error.text)) { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + shakeIfOff(); + }); } else { AndroidUtilities.runOnUIThread(() -> { try { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index a2334e487..28edacfc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -26,8 +26,13 @@ import android.os.Vibrator; import android.text.Editable; import android.text.InputFilter; import android.text.InputType; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -38,7 +43,8 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; -import android.widget.ViewAnimator; + +import androidx.annotation.NonNull; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; @@ -48,6 +54,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -64,20 +71,22 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextBlockCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CircularProgressDrawable; import org.telegram.ui.Components.CrossfadeDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; +import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.EditTextEmoji; import org.telegram.ui.Components.ImageUpdater; -import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.Components.EditTextBoldCursor; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkActionView; +import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgressView; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.TypefaceSpan; import java.util.ArrayList; @@ -790,11 +799,50 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC permanentLinkView.setUsers(0, null); privateContainer.addView(permanentLinkView); - checkTextView = new TextView(context); + checkTextView = new LinkSpanDrawable.LinksTextView(context) { + @Override + public void setText(CharSequence text, BufferType type) { + if (text != null) { + SpannableStringBuilder tagsString = AndroidUtilities.replaceTags(text.toString()); + int index = tagsString.toString().indexOf('\n'); + if (index >= 0) { + tagsString.replace(index, index + 1, " "); + tagsString.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_windowBackgroundWhiteRedText4)), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + TypefaceSpan[] spans = tagsString.getSpans(0, tagsString.length(), TypefaceSpan.class); + final String username = descriptionTextView == null || descriptionTextView.getText() == null ? "" : descriptionTextView.getText().toString(); + for (int i = 0; i < spans.length; ++i) { + tagsString.setSpan( + new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + Browser.openUrl(getContext(), "https://fragment.com/username/" + username); + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }, + tagsString.getSpanStart(spans[i]), + tagsString.getSpanEnd(spans[i]), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + tagsString.removeSpan(spans[i]); + } + text = tagsString; + } + super.setText(text, type); + } + }; + checkTextView.setLinkTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkText)); + checkTextView.setHighlightColor(Theme.getColor(Theme.key_windowBackgroundWhiteLinkSelection)); checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); checkTextView.setVisibility(View.GONE); - linkContainer.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 17, 3, 17, 7)); + checkTextView.setPadding(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(3), 0); + linkContainer.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 18, 3, 18, 7)); typeInfoCell = new TextInfoPrivacyCell(context); typeInfoCell.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); @@ -1179,7 +1227,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC } } } - if (name == null || name.length() < 5) { + if (name == null || name.length() < 4) { checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); checkTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); @@ -1209,14 +1257,24 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGreenText)); lastNameAvailable = true; } else { - if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + if (error != null && "USERNAME_INVALID".equals(error.text) && req.username.length() == 4) { + checkTextView.setText(LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } else if (error != null && "USERNAME_PURCHASE_AVAILABLE".equals(error.text)) { + if (req.username.length() == 4) { + checkTextView.setText(LocaleController.getString("UsernameInvalidShortPurchase", R.string.UsernameInvalidShortPurchase)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInUsePurchase", R.string.UsernameInUsePurchase)); + } + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText8)); + } else if (error != null && "CHANNELS_ADMIN_PUBLIC_TOO_MUCH".equals(error.text)) { + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); canCreatePublic = false; showPremiumIncreaseLimitDialog(); } else { + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); } - checkTextView.setTag(Theme.key_windowBackgroundWhiteRedText4); - checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); lastNameAvailable = false; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index fa022d527..e80e0e756 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -64,6 +64,7 @@ import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; import android.text.style.URLSpan; +import android.util.Pair; import android.util.Property; import android.util.SparseArray; import android.util.SparseIntArray; @@ -198,6 +199,7 @@ import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatActivityEnterTopView; import org.telegram.ui.Components.ChatActivityEnterView; +import org.telegram.ui.Components.ChatActivityInterface; import org.telegram.ui.Components.ChatAttachAlert; import org.telegram.ui.Components.ChatAttachAlertDocumentLayout; import org.telegram.ui.Components.ChatAvatarContainer; @@ -305,7 +307,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; @SuppressWarnings("unchecked") -public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate, LocationActivity.LocationActivityDelegate, ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate, FragmentContextView.ChatActivityInterface, FloatingDebugProvider { +public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate, LocationActivity.LocationActivityDelegate, ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate, ChatActivityInterface, FloatingDebugProvider { private final static boolean PULL_DOWN_BACK_FRAGMENT = false; private final static boolean DISABLE_PROGRESS_VIEW = true; private final static int SKELETON_DISAPPEAR_MS = 200; @@ -351,6 +353,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ActionBarMenuSubItem clearHistoryItem; private ActionBarMenuSubItem viewAsTopics; private ActionBarMenuSubItem closeTopicItem; + private ActionBarMenuSubItem openForumItem; private ClippingImageView animatingImageView; private RecyclerListView chatListView; private ChatListItemAnimator chatListItemAnimator; @@ -507,6 +510,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int reportType = -1; private MessageObject threadMessageObject; + private MessageObject topicStarterMessageObject; private boolean threadMessageVisible = true; private ArrayList threadMessageObjects; private MessageObject replyMessageHeaderObject; @@ -1179,6 +1183,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int search = 40; private final static int topic_close = 60; + private final static int open_forum = 61; private final static int id_chat_compose_panel = 1000; @@ -1681,7 +1686,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (!forceHistoryEmpty) { loading = true; } - if (isThreadChat()) { + if (isThreadChat() && !isTopic) { if (highlightMessageId == startLoadFromMessageId) { needSelectFromMessageId = true; } @@ -1695,11 +1700,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (startLoadFromMessageId == 0) { SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); - int messageId = sharedPreferences.getInt("diditem" + dialog_id, 0); + int messageId = sharedPreferences.getInt("diditem" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId()), 0); if (messageId != 0) { wasManualScroll = true; loadingFromOldPosition = true; - startLoadFromMessageOffset = sharedPreferences.getInt("diditemo" + dialog_id, 0); + startLoadFromMessageOffset = sharedPreferences.getInt("diditemo" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId()), 0); startLoadFromMessageId = messageId; } } else { @@ -1743,7 +1748,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not waitingForLoad.add(lastLoadIndex); if (startLoadFromDate != 0) { getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, startLoadFromDate, true, 0, classGuid, 4, 0, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++, isTopic); - } else if (startLoadFromMessageId != 0 && (!isThreadChat() || startLoadFromMessageId == highlightMessageId)) { + } else if (startLoadFromMessageId != 0 && (!isThreadChat() || startLoadFromMessageId == highlightMessageId || isTopic)) { startLoadFromMessageIdSaved = startLoadFromMessageId; if (migrated_to != 0) { mergeDialogId = migrated_to; @@ -2358,43 +2363,50 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateTopicButtons(); updateBottomOverlay(); updateTopPanel(true); + } else if (id == open_forum) { + TopicsFragment.prepareToSwitchAnimation(ChatActivity.this); +// Bundle bundle = new Bundle(); +// bundle.putLong("chat_id", -dialog_id); +// presentFragment(new TopicsFragment(bundle)); } } }); View backButton = actionBar.getBackButton(); - backButton.setOnLongClickListener(e -> { - scrimPopupWindow = BackButtonMenu.show(this, backButton, dialog_id, themeDelegate); - if (scrimPopupWindow != null) { - scrimPopupWindow.setOnDismissListener(() -> { - scrimPopupWindow = null; - menuDeleteItem = null; - scrimPopupWindowItems = null; - chatLayoutManager.setCanScrollVertically(true); - if (scrimPopupWindowHideDimOnDismiss) { - dimBehindView(false); - } else { - scrimPopupWindowHideDimOnDismiss = true; + backButton.setOnTouchListener(new LongPressListenerWithMovingGesture() { + @Override + public void onLongPress() { + scrimPopupWindow = BackButtonMenu.show(ChatActivity.this, backButton, dialog_id, getTopicId(), themeDelegate); + if (scrimPopupWindow != null) { + setSubmenu(scrimPopupWindow); + scrimPopupWindow.setOnDismissListener(() -> { + setSubmenu(null); + scrimPopupWindow = null; + menuDeleteItem = null; + scrimPopupWindowItems = null; + chatLayoutManager.setCanScrollVertically(true); + if (scrimPopupWindowHideDimOnDismiss) { + dimBehindView(false); + } else { + scrimPopupWindowHideDimOnDismiss = true; + } + if (chatActivityEnterView != null) { + chatActivityEnterView.getEditField().setAllowDrawCursor(true); + } + }); + chatListView.stopScroll(); + chatLayoutManager.setCanScrollVertically(false); + dimBehindView(backButton, 0.3f); + hideHints(false); + if (topUndoView != null) { + topUndoView.hide(true, 1); + } + if (undoView != null) { + undoView.hide(true, 1); } if (chatActivityEnterView != null) { - chatActivityEnterView.getEditField().setAllowDrawCursor(true); + chatActivityEnterView.getEditField().setAllowDrawCursor(false); } - }); - chatListView.stopScroll(); - chatLayoutManager.setCanScrollVertically(false); - dimBehindView(backButton, 0.3f); - hideHints(false); - if (topUndoView != null) { - topUndoView.hide(true, 1); } - if (undoView != null) { - undoView.hide(true, 1); - } - if (chatActivityEnterView != null) { - chatActivityEnterView.getEditField().setAllowDrawCursor(false); - } - return true; - } else { - return false; } }); actionBar.setInterceptTouchEventListener((view, motionEvent) -> { @@ -2834,6 +2846,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateBotButtons(); } } + if (ChatObject.isForum(currentChat) && isTopic) { + if (getParentLayout() != null && getParentLayout().getFragmentStack() != null) { + boolean hasMyForum = false; + for (int i = 0; i < getParentLayout().getFragmentStack().size(); ++i) { + BaseFragment fragment = getParentLayout().getFragmentStack().get(i); + if (fragment instanceof TopicsFragment && ((TopicsFragment) fragment).getDialogId() == dialog_id) { + hasMyForum = true; + break; + } + } + + if (!hasMyForum) { + openForumItem = headerItem.addSubItem(open_forum, R.drawable.msg_discussion, LocaleController.getString("OpenAllTopics", R.string.OpenAllTopics), themeDelegate); + } + } + } if (currentChat != null && forumTopic != null) { closeTopicItem = headerItem.addSubItem(topic_close, R.drawable.msg_topic_close, LocaleController.getString("CloseTopic", R.string.CloseTopic), themeDelegate); closeTopicItem.setVisibility(currentChat != null && ChatObject.canManageTopic(currentAccount, currentChat, forumTopic) && forumTopic != null && !forumTopic.closed ? View.VISIBLE : View.GONE); @@ -2986,6 +3014,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (mentionContainer != null) { mentionContainer.onPanTransitionEnd(); } + if (voiceHintTextView != null && voiceHintTextView.getVisibility() == View.VISIBLE) { + voiceHintTextView.showForView(chatActivityEnterView.getAudioVideoButtonContainer(), false); + } } @Override @@ -3023,6 +3054,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((DialogsActivity)mainFragment).setPanTranslationOffset(y); } } + if (voiceHintTextView != null && voiceHintTextView.getVisibility() == View.VISIBLE) { + voiceHintTextView.showForView(chatActivityEnterView.getAudioVideoButtonContainer(), false); + } } @Override @@ -3094,7 +3128,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { expandY = chatActivityEnterView.getY(); } - if (scrimView != null || chatActivityEnterView != null && chatActivityEnterView.isStickersExpanded() && ev.getY() < expandY) { + if ((scrimView != null && scrimView != actionBar.getBackButton()) || chatActivityEnterView != null && chatActivityEnterView.isStickersExpanded() && ev.getY() < expandY) { return false; } @@ -4309,6 +4343,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (textSelectionHelper != null && textSelectionHelper.isSelectionMode()) { textSelectionHelper.invalidate(); } + isSkeletonVisible(); } private void setGroupTranslationX(ChatMessageCell view, float dx) { @@ -4810,8 +4845,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not maxTop = top; } } - if (maxTop <= 0) { - checkDispatchHideSkeletons(true); + if (maxTop <= chatListViewPaddingTop) { + checkDispatchHideSkeletons(fragmentBeginToShow); } boolean visible = (!endReached[0] || mergeDialogId != 0 && !endReached[1] || messages.isEmpty()) && loading && maxTop > 0 && (messages.isEmpty() ? animateProgressViewTo : childHeight != 0); @@ -4904,12 +4939,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject.GroupedMessages group = ((ChatMessageCell) v).getCurrentMessagesGroup(); Rect bounds = ((ChatMessageCell) v).getCurrentBackgroundDrawable(true).getBounds(); int newTop = (int) (v.getTop() + bounds.top + (group != null ? group.transitionParams.top + group.transitionParams.offsetTop : 0)); - int top = messages.size() <= 2 && isSkeletonVisible() ? AndroidUtilities.lerp(lastTop, newTop, v.getAlpha()) : v.getAlpha() == 1f ? newTop : lastTop; + int top = startMessageAppearTransitionMs == 0 && isSkeletonVisible() ? AndroidUtilities.lerp(lastTop, newTop, v.getAlpha()) : v.getAlpha() == 1f ? newTop : lastTop; if (top < lastTop) { lastTop = top; } } else if (v instanceof ChatActionCell) { - int top = messages.size() <= 2 && isSkeletonVisible() ? AndroidUtilities.lerp(lastTop, v.getTop(), v.getAlpha()) : v.getAlpha() == 1f ? v.getTop() : lastTop; + int top = startMessageAppearTransitionMs == 0 && isSkeletonVisible() ? AndroidUtilities.lerp(lastTop, v.getTop(), v.getAlpha()) : v.getAlpha() == 1f ? v.getTop() : lastTop; if (top < lastTop) { lastTop = top; } @@ -4962,6 +4997,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not servicePaint.setAlpha(wasServiceAlpha); skeletonPaint.setAlpha(alpha); + invalidated = false; invalidate(); } else if (System.currentTimeMillis() - startMessageAppearTransitionMs > SKELETON_DISAPPEAR_MS) { messageSkeletons.clear(); @@ -5365,6 +5401,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean drawChild(Canvas canvas, View child, long drawingTime) { if (isSkeletonVisible()) { + invalidated = false; invalidate(); } @@ -5866,7 +5903,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public int getStarForFixGap() { int padding = (int) chatListViewPaddingTop; - if (isThreadChat() && !isTopic && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + if (isThreadChat() && (!isTopic || topicStarterMessageObject != null) && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } return padding; @@ -6011,7 +6048,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int i = 0; i < n; i++) { View child = chatListView.getChildAt(i); float padding = chatListViewPaddingTop; - if (isThreadChat() && !isTopic && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + if (isThreadChat() && (!isTopic || topicStarterMessageObject != null) && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } if (chatListView.getChildAdapterPosition(child) == chatAdapter.getItemCount() - 1) { @@ -7632,6 +7669,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not topUndoView.showWithAction(0, UndoView.ACTION_HINT_SWIPE_TO_REPLY, null, null); } } + if (ChatObject.isForum(currentChat) && !isTopic && replyingMessageObject != null) { + int topicId = replyingMessageObject.replyToForumTopic != null ? replyingMessageObject.replyToForumTopic.id : MessageObject.getTopicId(replyingMessageObject.messageOwner); + if (topicId != 0) { + getMediaDataController().cleanDraft(dialog_id, topicId, false); + } + } + hideFieldPanel(notify, scheduleDate, true); if (chatActivityEnterView != null && chatActivityEnterView.getEmojiView() != null) { chatActivityEnterView.getEmojiView().onMessageSend(); @@ -8152,6 +8196,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterTopView.addView(replyCloseImageView, LayoutHelper.createFrame(52, 46, Gravity.RIGHT | Gravity.TOP, 0, 0.5f, 0, 0)); replyCloseImageView.setOnClickListener(v -> { if (forwardingMessages == null || forwardingMessages.messages.isEmpty()) { + if (ChatObject.isForum(currentChat) && !isTopic && replyingMessageObject != null) { + int topicId = MessageObject.getTopicId(replyingMessageObject.messageOwner); + if (topicId != 0) { + getMediaDataController().cleanDraft(dialog_id, topicId, false); + } + } showFieldPanel(false, null, null, null, foundWebPage, true, 0, true, true); } else { openAnotherForward(); @@ -9394,6 +9444,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (object != null) { fragment.pinnedMessageObjects.put(id, object); + fragment.updatePinnedTopicStarterMessage(); } } fragment.loadedPinnedMessagesCount = loadedPinnedMessagesCount; @@ -9706,7 +9757,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int adapterPosition = chatListView.getChildAdapterPosition(child); if (adapterPosition == chatAdapter.getItemCount() - 1) { float padding = chatListViewPaddingTop; - if (isThreadChat() && !isTopic && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + if (isThreadChat() && (!isTopic || topicStarterMessageObject != null) && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } if (child.getTop() > padding) { @@ -11840,6 +11891,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyObjectText = messageObjectToReply.messageTextShort; } AnimatedEmojiSpan.applyFontMetricsForString(replyObjectText, replyObjectTextView.getPaint()); + } else if (messageObjectToReply.replyToForumTopic != null) { + replyObjectText = ForumUtilities.getTopicSpannedName(messageObjectToReply.replyToForumTopic, replyObjectTextView.getPaint()); } else if (messageObjectToReply.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { replyObjectText = Emoji.replaceEmoji(messageObjectToReply.messageOwner.media.game.title, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false); sourceText = messageObjectToReply.messageOwner.media.game.title; @@ -12502,6 +12555,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean blurEnabled = SharedConfig.chatBlurEnabled() && Color.alpha(Theme.getColor(Theme.key_chat_BlurAlpha)) != 255; + MessageObject messageStarter = isTopic ? topicStarterMessageObject : threadMessageObject; + for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); MessageObject messageObject = null; @@ -12558,7 +12613,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messageCell.setParentBounds(chatListViewPaddingTop - chatListViewPaddingVisibleOffset - AndroidUtilities.dp(4), chatListView.getMeasuredHeight() - blurredViewBottomOffset); messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, keyboardOffset, view.getY() + (isKeyboardVisible() ? chatListView.getTop() : actionBar.getMeasuredHeight()) - contentView.getBackgroundTranslationY(), contentView.getMeasuredWidth(), contentView.getBackgroundSizeY(), blurredViewTopOffset, blurredViewBottomOffset); markSponsoredAsRead(messageObject); - if (!threadMessageVisible && threadMessageObject != null && messageObject == threadMessageObject && messageCell.getBottom() > chatListViewPaddingTop) { + if (!threadMessageVisible && messageStarter != null && (messageObject == messageStarter || isTopic && messageObject != null && messageObject.getId() == messageStarter.getId()) && messageCell.getBottom() > chatListViewPaddingTop) { threadMessageVisible = true; } if (videoPlayerContainer != null && (messageObject.isVideo() || messageObject.isRoundVideo()) && !messageObject.isVoiceTranscriptionOpen() && MediaController.getInstance().isPlayingMessage(messageObject)) { @@ -12817,7 +12872,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideFloatingDateView(true); floatingDateViewOffset = 0; } - if (isThreadChat() && !isTopic) { + if (isThreadChat()) { if (previousThreadMessageVisible != threadMessageVisible) { updatePinnedMessageView(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150); } @@ -15444,6 +15499,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!postponedScroll) { chatAdapter.notifyDataSetChanged(true); } + if (isTopic && startLoadFromMessageId == getTopicId() && messArr.size() > 0 && messages.size() > 0) { + scrollToMessage = messages.get(messArr.size() - 1); + } if (scrollToMessage != null) { addSponsoredMessages(!isFirstLoading); int yOffset; @@ -17079,6 +17137,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + updatePinnedTopicStarterMessage(); } else if (id == NotificationCenter.didReceivedWebpages) { ArrayList arrayList = (ArrayList) args[0]; boolean updated = false; @@ -17276,12 +17335,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not SparseArray array = channelReplies.get(dialog_id); boolean hasChatInBack = false; - if (threadMessageObject != null && parentLayout != null) { + if (threadMessageObject != null && !isTopic && parentLayout != null) { for (int a = 0, N = parentLayout.getFragmentStack().size() - 1; a < N; a++) { BaseFragment fragment = parentLayout.getFragmentStack().get(a); if (fragment != this && fragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode()) { + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getTopicId() == getTopicId() && chatActivity.getChatMode() == getChatMode()) { hasChatInBack = true; break; } @@ -18717,12 +18776,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean hasChatInBack = false; boolean updatedReplies = false; - if (threadMessageObject != null && parentLayout != null) { + if (threadMessageObject != null && !isTopic && parentLayout != null) { for (int a = 0, N = parentLayout.getFragmentStack().size() - 1; a < N; a++) { BaseFragment fragment = parentLayout.getFragmentStack().get(a); if (fragment != this && fragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode()) { + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && getTopicId() == getTopicId() && chatActivity.getChatMode() == getChatMode()) { hasChatInBack = true; break; } @@ -19084,6 +19143,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + updatePinnedTopicStarterMessage(); } private void migrateToNewChat(MessageObject obj) { @@ -19365,7 +19425,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not BaseFragment fragment = parentLayout.getFragmentStack().get(a); if (fragment != this && fragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode() && chatActivity.threadMessageId == threadMessageId && chatActivity.reportType == reportType) { + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getTopicId() == getTopicId() && chatActivity.getChatMode() == getChatMode() && chatActivity.threadMessageId == threadMessageId && chatActivity.reportType == reportType) { fragment.removeSelfFromStack(); break; } @@ -19899,9 +19959,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void updateTopicHeader() { avatarContainer.setTitle(forumTopic.title); - if (currentChat != null) { - avatarContainer.setSubtitle(LocaleController.formatString("TopicProfileStatus", R.string.TopicProfileStatus, currentChat.title)); - } updateTopicTitleIcon(); } @@ -20058,6 +20115,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if ((isThreadChat() && !isTopic) || pinnedListButton == null) { return; } + if (!fragmentOpened) { + animated = false; + } boolean show = pinnedMessageIds.size() > 1 && !pinnedMessageButtonShown; boolean visible = pinnedListButton.getTag() != null; boolean progressIsVisible = pinnedProgress.getTag() != null; @@ -20157,7 +20217,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int pinned_msg_id; boolean changed = false; MessageObject pinnedMessageObject; - if (isThreadChat() && !isTopic) { + if (isThreadChat() && threadMessageVisible) { + pinnedMessageObject = null; + pinned_msg_id = 0; + } else if (isThreadChat() && !isTopic) { if (!threadMessageVisible) { pinnedMessageObject = threadMessageObject; pinned_msg_id = threadMessageId; @@ -21455,10 +21518,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatMode == 0) { CharSequence[] message = new CharSequence[]{draftMessage}; ArrayList entities = getMediaDataController().getEntities(message, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101); - getMediaDataController().saveDraft(dialog_id, threadMessageId, message[0], entities, (replyMessage != null && !replyMessage.isTopicMainMessage) ? replyMessage.messageOwner : null, !searchWebpage); + int draftThreadId; + if (ChatObject.isForum(currentChat) && !isTopic && replyMessage != null) { + if (replyMessage.replyToForumTopic != null) { + draftThreadId = replyMessage.replyToForumTopic.id; + } else { + draftThreadId = MessageObject.getTopicId(replyMessage.messageOwner); + } + } else { + draftThreadId = threadMessageId; + } + getMediaDataController().saveDraft(dialog_id, draftThreadId, message[0], entities, (replyMessage != null && !replyMessage.isTopicMainMessage && replyMessage.replyToForumTopic == null) ? replyMessage.messageOwner : null, !searchWebpage); getMessagesController().cancelTyping(0, dialog_id, threadMessageId); - if (!pausedOnLastMessage && !firstLoading) { + if (!pausedOnLastMessage && !firstLoading && (!isThreadChat() || isTopic)) { SharedPreferences.Editor editor = MessagesController.getNotificationsSettings(currentAccount).edit(); int messageId = 0; int offset = 0; @@ -21522,12 +21595,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (messageId != 0) { - editor.putInt("diditem" + dialog_id, messageId); - editor.putInt("diditemo" + dialog_id, offset); + editor.putInt("diditem" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId()), messageId); + editor.putInt("diditemo" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId()), offset); } else { pausedOnLastMessage = true; - editor.remove("diditem" + dialog_id); - editor.remove("diditemo" + dialog_id); + editor.remove("diditem" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId())); + editor.remove("diditemo" + NotificationsController.getSharedPrefKey(dialog_id, getTopicId())); } editor.commit(); } @@ -21554,8 +21627,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView == null || chatMode != 0) { return; } - TLRPC.DraftMessage draftMessage = getMediaDataController().getDraft(dialog_id, threadMessageId); - TLRPC.Message draftReplyMessage = draftMessage != null && draftMessage.reply_to_msg_id != 0 ? getMediaDataController().getDraftMessage(dialog_id, threadMessageId) : null; + TLRPC.DraftMessage draftMessage = null; + Integer topicId = null; + if (ChatObject.isForum(currentChat) && !isTopic) { + Pair pair = getMediaDataController().getOneThreadDraft(dialog_id);; + if (pair != null) { + topicId = pair.first; + draftMessage = pair.second; + } + } else { + draftMessage = getMediaDataController().getDraft(dialog_id, threadMessageId); + } + TLRPC.Message draftReplyMessage = draftMessage != null && draftMessage.reply_to_msg_id != 0 ? getMediaDataController().getDraftMessage(dialog_id, topicId != null ? topicId : threadMessageId) : null; if (chatActivityEnterView.getFieldText() == null) { if (draftMessage != null) { chatActivityEnterView.setWebPage(null, !draftMessage.no_webpage); @@ -21643,6 +21726,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyingMessageObject = new MessageObject(currentAccount, draftReplyMessage, getMessagesController().getUsers(), false, false); showFieldPanelForReply(replyingMessageObject); updateBottomOverlay(); + } else if (topicId != null && topicId != 0 && currentChat != null) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null && topic.topicStartMessage != null) { + replyingMessageObject = new MessageObject(currentAccount, topic.topicStartMessage, getMessagesController().getUsers(), false, false); + replyingMessageObject.replyToForumTopic = topic; + showFieldPanelForReply(replyingMessageObject); + updateBottomOverlay(); + } } } @@ -22085,7 +22176,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final ArrayList options = new ArrayList<>(); View optionsView = null; - if (!getUserConfig().isPremium() && !getMessagesController().premiumLocked && message.getDocument() != null && message.getDocument().size >= 500 * 1024 * 1024 && FileLoader.getInstance(currentAccount).isLoadingFile(FileLoader.getAttachFileName(message.getDocument()))) { + if (!getUserConfig().isPremium() && !getMessagesController().premiumLocked && message.getDocument() != null && message.getDocument().size >= 300 * 1024 * 1024 && FileLoader.getInstance(currentAccount).isLoadingFile(FileLoader.getAttachFileName(message.getDocument()))) { items.add(LocaleController.getString(R.string.PremiumSpeedPromo)); options.add(OPTION_SPEED_PROMO); icons.add(R.drawable.msg_speed); @@ -22102,7 +22193,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (index != -1) { - FileLoader.getInstance(currentAccount).loadFile(premiumPromo.videos.get(index), null, FileLoader.PRIORITY_HIGH, 0); + FileLoader.getInstance(currentAccount).loadFile(premiumPromo.videos.get(index), premiumPromo, FileLoader.PRIORITY_HIGH, 0); } } } @@ -24599,7 +24690,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { MessagesStorage.TopicKey topicKey = dids.get(0); long did = topicKey.dialogId; - if (did != dialog_id || chatMode == MODE_PINNED) { + if (did != dialog_id || getTopicId() != topicKey.topicId || chatMode == MODE_PINNED) { Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", scrollToTopOnResume); if (DialogObject.isEncryptedDialog(did)) { @@ -24628,7 +24719,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragment.finishFragment(); } } else { - fragment.finishFragment(); + List fragments = new ArrayList<>(getParentLayout().getFragmentStack()); + if (!fragments.isEmpty() && fragments.get(fragments.size() - 1) == fragment) { + fragment.finishFragment(); + } else { + int fragmentIndex = fragments.indexOf(fragment); + if (fragmentIndex > 0) { + for (int i = fragmentIndex; i < fragments.size(); i++) { + if (i == fragments.size() - 1) { + fragments.get(i).finishFragment(); + } else { + fragment.removeSelfFromStack(); + } + } + } + } moveScrollToLastMessage(false); showFieldPanelForForward(true, fmessages); if (AndroidUtilities.isTablet()) { @@ -24736,10 +24841,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (isTopic) { replyingMessageObject.isTopicMainMessage = true; } + updatePinnedTopicStarterMessage(); updateTopPanel(false); updateBottomOverlay(); } + private void updatePinnedTopicStarterMessage() { + topicStarterMessageObject = isTopic && !pinnedMessageObjects.isEmpty() && pinnedMessageIds.size() == 1 ? pinnedMessageObjects.get(pinnedMessageIds.get(0)) : null; + if (isTopic && topicStarterMessageObject != null && topicStarterMessageObject.messageOwner != null && forumTopic != null && !MessageObject.peersEqual(forumTopic.from_id, topicStarterMessageObject.messageOwner.from_id) && !MessageObject.peersEqual(currentChat, topicStarterMessageObject.messageOwner.from_id)) { + topicStarterMessageObject = null; + } + } + public void setHighlightMessageId(int id) { highlightMessageId = id; } @@ -26682,6 +26795,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } + @Override + public void didPressTopicButton(ChatMessageCell cell) { + MessageObject message = cell.getMessageObject(); + if (message != null) { + int topicId = MessageObject.getTopicId(message.messageOwner); + if (topicId != 0) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(currentChat.id, topicId); + if (topic != null) { + ForumUtilities.openTopic(ChatActivity.this, currentChat.id, topic, message.getId()); + } + } + } + } + @Override public void didPressExtendedMediaPreview(ChatMessageCell cell, TLRPC.KeyboardButton button) { getSendMessagesHelper().sendCallback(true, cell.getMessageObject(), button, ChatActivity.this); @@ -29716,6 +29843,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return skeleton; } + @Override + public SizeNotifierFrameLayout getContentView() { + return contentView; + } + private final static class MessageSkeleton { int width; int height; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 03ade5e71..24ee9efa8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -19,8 +19,13 @@ import android.graphics.drawable.Drawable; import android.os.Vibrator; import android.text.Editable; import android.text.InputType; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextPaint; import android.text.TextUtils; import android.text.TextWatcher; +import android.text.style.ClickableSpan; +import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; @@ -41,6 +46,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -69,6 +75,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LinkActionView; import org.telegram.ui.Components.Premium.LimitReachedBottomSheet; import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.TypefaceSpan; import java.util.ArrayList; import java.util.HashMap; @@ -464,7 +471,43 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe permanentLinkView.setUsers(0, null); privateContainer.addView(permanentLinkView); - checkTextView = new TextInfoPrivacyCell(context); + checkTextView = new TextInfoPrivacyCell(context) { + @Override + public void setText(CharSequence text) { + if (text != null) { + SpannableStringBuilder tagsString = AndroidUtilities.replaceTags(text.toString()); + int index = tagsString.toString().indexOf('\n'); + if (index >= 0) { + tagsString.replace(index, index + 1, " "); + tagsString.setSpan(new ForegroundColorSpan(getThemedColor(Theme.key_windowBackgroundWhiteRedText4)), 0, index, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + TypefaceSpan[] spans = tagsString.getSpans(0, tagsString.length(), TypefaceSpan.class); + final String username = usernameTextView == null || usernameTextView.getText() == null ? "" : usernameTextView.getText().toString(); + for (int i = 0; i < spans.length; ++i) { + tagsString.setSpan( + new ClickableSpan() { + @Override + public void onClick(@NonNull View view) { + Browser.openUrl(getContext(), "https://fragment.com/username/" + username); + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(false); + } + }, + tagsString.getSpanStart(spans[i]), + tagsString.getSpanEnd(spans[i]), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + tagsString.removeSpan(spans[i]); + } + text = tagsString; + } + super.setText(text); + } + }; checkTextView.setBackgroundDrawable(Theme.getThemedDrawable(context, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); checkTextView.setBottomPadding(6); linearLayout.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); @@ -1344,7 +1387,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe } } } - if (name == null || name.length() < 5) { + if (name == null || name.length() < 4) { if (isChannel) { checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); } else { @@ -1374,13 +1417,23 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe checkTextView.setTextColor(Theme.key_windowBackgroundWhiteGreenText); lastNameAvailable = true; } else { - if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + if (error != null && "USERNAME_INVALID".equals(error.text) && req.username.length() == 4) { + checkTextView.setText(LocaleController.getString("UsernameInvalidShort", R.string.UsernameInvalidShort)); + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteRedText4)); + } else if (error != null && "USERNAME_PURCHASE_AVAILABLE".equals(error.text)) { + if (req.username.length() == 4) { + checkTextView.setText(LocaleController.getString("UsernameInvalidShortPurchase", R.string.UsernameInvalidShortPurchase)); + } else { + checkTextView.setText(LocaleController.getString("UsernameInUsePurchase", R.string.UsernameInUsePurchase)); + } + checkTextView.setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText8)); + } else if (error != null && "CHANNELS_ADMIN_PUBLIC_TOO_MUCH".equals(error.text)) { canCreatePublic = false; showPremiumIncreaseLimitDialog(); } else { checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + checkTextView.setTextColor(Theme.key_windowBackgroundWhiteRedText4); } - checkTextView.setTextColor(Theme.key_windowBackgroundWhiteRedText4); lastNameAvailable = false; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedColor.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedColor.java new file mode 100644 index 000000000..6b9dfb957 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedColor.java @@ -0,0 +1,174 @@ +package org.telegram.ui.Components; + + +import android.animation.TimeInterpolator; +import android.os.SystemClock; +import android.view.View; + +import androidx.core.graphics.ColorUtils; +import androidx.core.math.MathUtils; + +public class AnimatedColor { + + private View parent; + private Runnable invalidate; + private int value; + private int targetValue; + private boolean firstSet; + + private long transitionDelay = 0; + private long transitionDuration = 200; + private TimeInterpolator transitionInterpolator = CubicBezierInterpolator.DEFAULT; + private boolean transition; + private long transitionStart; + private int startValue; + + public AnimatedColor() { + this.parent = null; + this.firstSet = true; + } + + public AnimatedColor(long transitionDuration, TimeInterpolator transitionInterpolator) { + this.parent = null; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + + public AnimatedColor(long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.parent = null; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + + public AnimatedColor(View parentToInvalidate) { + this.parent = parentToInvalidate; + this.firstSet = true; + } + + public AnimatedColor(View parentToInvalidate, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.parent = parentToInvalidate; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + + public AnimatedColor(View parentToInvalidate, long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.parent = parentToInvalidate; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + + + public AnimatedColor(Runnable invalidate) { + this.invalidate = invalidate; + this.firstSet = true; + } + + public AnimatedColor(Runnable invalidate, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.invalidate = invalidate; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = true; + } + + public AnimatedColor(int initialValue, View parentToInvalidate) { + this.parent = parentToInvalidate; + this.value = targetValue = initialValue; + this.firstSet = false; + } + + public AnimatedColor(int initialValue, Runnable invalidate) { + this.invalidate = invalidate; + this.value = targetValue = initialValue; + this.firstSet = false; + } + + public AnimatedColor(int initialValue, View parentToInvalidate, long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.parent = parentToInvalidate; + this.value = targetValue = initialValue; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = false; + } + + public AnimatedColor(int initialValue, Runnable invalidate, long transitionDelay, long transitionDuration, TimeInterpolator transitionInterpolator) { + this.invalidate = invalidate; + this.value = targetValue = initialValue; + this.transitionDelay = transitionDelay; + this.transitionDuration = transitionDuration; + this.transitionInterpolator = transitionInterpolator; + this.firstSet = false; + } + + public int get() { + return value; + } + + // set() must be called inside onDraw/dispatchDraw + // the main purpose of AnimatedColor is to interpolate between abrupt changing states + + public int set(int mustBeColor) { + return this.set(mustBeColor, false); + } + + public int set(int mustBeColor, boolean force) { + final long now = SystemClock.elapsedRealtime(); + if (force || transitionDuration <= 0 || firstSet) { + value = targetValue = mustBeColor; + transition = false; + firstSet = false; + } else if (targetValue != mustBeColor) { + transition = true; + targetValue = mustBeColor; + startValue = value; + transitionStart = now; + } + if (transition) { + final float t = MathUtils.clamp((now - transitionStart - transitionDelay) / (float) transitionDuration, 0, 1); + if (now - transitionStart >= transitionDelay) { + if (transitionInterpolator == null) { + value = ColorUtils.blendARGB(startValue, targetValue, t); + } else { + value = ColorUtils.blendARGB(startValue, targetValue, transitionInterpolator.getInterpolation(t)); + } + } + if (t >= 1f) { + transition = false; + } else { + if (parent != null) { + parent.invalidate(); + } + if (invalidate != null) { + invalidate.run(); + } + } + } + return value; + } + + public float getTransitionProgress() { + if (!transition) { + return 0; + } + final long now = SystemClock.elapsedRealtime(); + return MathUtils.clamp((now - transitionStart - transitionDelay) / (float) transitionDuration, 0, 1); + } + + public float getTransitionProgressInterpolated() { + if (transitionInterpolator != null) { + return transitionInterpolator.getInterpolation(getTransitionProgress()); + } else { + return getTransitionProgress(); + } + } + + public void setParent(View parent) { + this.parent = parent; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java index 95b3a3429..ac097c8b1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiDrawable.java @@ -38,6 +38,7 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.Premium.PremiumLockIconView; import java.util.ArrayList; import java.util.HashMap; @@ -687,6 +688,28 @@ public class AnimatedEmojiDrawable extends Drawable { return imageReceiver; } + private static HashMap dominantColors; + public static int getDominantColor(AnimatedEmojiDrawable yourDrawable) { + if (yourDrawable == null) { + return 0; + } + long documentId = yourDrawable.getDocumentId(); + if (documentId == 0) { + return 0; + } + if (dominantColors == null) { + dominantColors = new HashMap<>(); + } + Integer color = dominantColors.get(documentId); + if (color == null) { + if (yourDrawable.getImageReceiver() != null && yourDrawable.getImageReceiver().getBitmap() != null) { + dominantColors.put(documentId, color = PremiumLockIconView.getDominantColor(yourDrawable.getImageReceiver().getBitmap())); + } + } + return color == null ? 0 : color; + } + + public static class WrapSizeDrawable extends Drawable { private Drawable drawable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java index 3c6c25f5e..c093e2ce9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedEmojiSpan.java @@ -34,6 +34,7 @@ public class AnimatedEmojiSpan extends ReplacementSpan { private float scale; public boolean standard; public boolean full = false; + public boolean top = false; private Paint.FontMetricsInt fontMetrics; private float size = AndroidUtilities.dp(20); @@ -101,6 +102,10 @@ public class AnimatedEmojiSpan extends ReplacementSpan { @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + if (fm == null && top) { + fm = paint.getFontMetricsInt(); + } + int ascent = fm == null ? 0 : fm.ascent, descent = fm == null ? 0 : fm.descent; if (fontMetrics == null) { int sz = (int) size; @@ -137,6 +142,11 @@ public class AnimatedEmojiSpan extends ReplacementSpan { } } } + if (fm != null && top) { + int diff = ((ascent - fm.ascent) + (descent - fm.descent)) / 2; + fm.ascent += diff; + fm.descent -= diff; + } return measuredSize - 1; } @@ -221,7 +231,7 @@ public class AnimatedEmojiSpan extends ReplacementSpan { public SpansChunk spansChunk; public boolean insideSpoiler; - ImageReceiver.BackgroundThreadDrawHolder backgroundDrawHolder; + private ImageReceiver.BackgroundThreadDrawHolder[] backgroundDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; public AnimatedEmojiHolder(View view, boolean invalidateInParent) { this.view = view; @@ -232,7 +242,7 @@ public class AnimatedEmojiSpan extends ReplacementSpan { return drawableBounds.bottom < boundTop || drawableBounds.top > boundBottom; } - public void prepareForBackgroundDraw(long updateTime) { + public void prepareForBackgroundDraw(long updateTime, int threadIndex) { if (drawable == null) { return; } @@ -245,16 +255,16 @@ public class AnimatedEmojiSpan extends ReplacementSpan { } imageReceiver.setAlpha(alpha); imageReceiver.setImageCoords(drawableBounds); - backgroundDrawHolder = imageReceiver.setDrawInBackgroundThread(backgroundDrawHolder); - backgroundDrawHolder.overrideAlpha = alpha; - backgroundDrawHolder.setBounds(drawableBounds); - backgroundDrawHolder.time = updateTime; + backgroundDrawHolder[threadIndex] = imageReceiver.setDrawInBackgroundThread(backgroundDrawHolder[threadIndex], threadIndex); + backgroundDrawHolder[threadIndex].overrideAlpha = alpha; + backgroundDrawHolder[threadIndex].setBounds(drawableBounds); + backgroundDrawHolder[threadIndex].time = updateTime; } } - public void releaseDrawInBackground() { - if (backgroundDrawHolder != null) { - backgroundDrawHolder.release(); + public void releaseDrawInBackground(int threadIndex) { + if (backgroundDrawHolder[threadIndex] != null) { + backgroundDrawHolder[threadIndex].release(); } } @@ -667,8 +677,8 @@ public class AnimatedEmojiSpan extends ReplacementSpan { public void drawInBackground(Canvas canvas) { for (int i = 0; i < backgroundHolders.size(); i++) { AnimatedEmojiHolder holder = backgroundHolders.get(i); - if (holder != null && holder.backgroundDrawHolder != null) { - holder.drawable.draw(canvas, holder.backgroundDrawHolder, true); + if (holder != null && holder.backgroundDrawHolder[threadIndex] != null) { + holder.drawable.draw(canvas, holder.backgroundDrawHolder[threadIndex], true); } } } @@ -695,9 +705,7 @@ public class AnimatedEmojiSpan extends ReplacementSpan { backgroundHolders.remove(i--); continue; } - if (holder != null) { - holder.prepareForBackgroundDraw(time); - } + holder.prepareForBackgroundDraw(time, threadIndex); } } @@ -705,7 +713,7 @@ public class AnimatedEmojiSpan extends ReplacementSpan { public void onFrameReady() { for (int i = 0; i < backgroundHolders.size(); i++) { if (backgroundHolders.get(i) != null) { - backgroundHolders.get(i).releaseDrawInBackground(); + backgroundHolders.get(i).releaseDrawInBackground(threadIndex); } } backgroundHolders.clear(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java index a3b695eb7..98e6e64f1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -28,6 +28,7 @@ import android.view.View; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimatedFileDrawableStream; import org.telegram.messenger.DispatchQueue; +import org.telegram.messenger.DispatchQueuePoolBackground; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLocation; @@ -109,16 +110,16 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, private RectF actualDrawRect = new RectF(); - private BitmapShader renderingShader; - private BitmapShader nextRenderingShader; - private BitmapShader backgroundShader; + private BitmapShader[] renderingShader = new BitmapShader[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private BitmapShader[] nextRenderingShader = new BitmapShader[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private BitmapShader[] backgroundShader = new BitmapShader[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; private BitmapShader renderingShaderBackgroundDraw; private int[] roundRadius = new int[4]; private int[] roundRadiusBackup; - private Matrix shaderMatrix = new Matrix(); - private Path roundPath = new Path(); + private Matrix[] shaderMatrix = new Matrix[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Path[] roundPath = new Path[1 + DrawingInBackgroundThreadDrawable.THREAD_COUNT]; private static float[] radii = new float[8]; private Matrix shaderMatrixBackgroundDraw; @@ -139,8 +140,10 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, private float scaleFactor = 1f; public boolean isWebmSticker; private final TLRPC.Document document; - private RectF dstRectBackground; - private Paint backgroundPaint; + private RectF[] dstRectBackground = new RectF[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Paint[] backgroundPaint = new Paint[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Matrix[] shaderMatrixBackground = new Matrix[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Path[] roundPathBackground = new Path[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; private View parentView; private ArrayList secondParentViews = new ArrayList<>(); @@ -175,16 +178,21 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, private Runnable uiRunnableGenerateCache = new Runnable() { @Override public void run() { - if (!isRecycled && !destroyWhenDone && !generatingCache) { + if (!isRecycled && !destroyWhenDone && !generatingCache && cacheGenRunnable == null) { startTime = System.currentTimeMillis(); if (RLottieDrawable.lottieCacheGenerateQueue == null) { RLottieDrawable.createCacheGenQueue(); } generatingCache = true; loadFrameTask = null; + BitmapsCache.incrementTaskCounter(); RLottieDrawable.lottieCacheGenerateQueue.postRunnable(cacheGenRunnable = () -> { bitmapsCache.createCache(); AndroidUtilities.runOnUIThread(() -> { + if (cacheGenRunnable != null) { + BitmapsCache.decrementTaskCounter(); + cacheGenRunnable = null; + } generatingCache = false; scheduleNextGetFrame(); }); @@ -241,7 +249,10 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, loadFrameTask = null; nextRenderingBitmap = backgroundBitmap; nextRenderingBitmapTime = backgroundBitmapTime; - nextRenderingShader = backgroundShader; + for (int i = 0; i < backgroundShader.length; i++) { + nextRenderingShader[i] = backgroundShader[i]; + } + if (isRestarted) { isRestarted = false; repeatCount++; @@ -342,8 +353,8 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, } catch (Throwable e) { FileLog.e(e); } - if (backgroundShader == null && backgroundBitmap != null && hasRoundRadius()) { - backgroundShader = new BitmapShader(backgroundBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (backgroundShader[0] == null && backgroundBitmap != null && hasRoundRadius()) { + backgroundShader[0] = new BitmapShader(backgroundBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); } } boolean seekWas = false; @@ -508,6 +519,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, } private Runnable cancelCache; + public void checkCacheCancel() { if (bitmapsCache == null) { return; @@ -591,7 +603,9 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, isRunning = false; isRecycled = true; if (cacheGenRunnable != null) { + BitmapsCache.decrementTaskCounter(); RLottieDrawable.lottieCacheGenerateQueue.cancelRunnable(cacheGenRunnable); + cacheGenRunnable = null; } if (loadFrameTask == null) { if (nativePtr != 0) { @@ -690,7 +704,7 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, } private void scheduleNextGetFrame() { - if (loadFrameTask != null || !canLoadFrames() || destroyWhenDone || !isRunning && (!decodeSingleFrame || decodeSingleFrame && singleFrameDecoded) || parents.size() == 0 && !ignoreNoParent || generatingCache) { + if (loadFrameTask != null || nextRenderingBitmap != null || !canLoadFrames() || destroyWhenDone || !isRunning && (!decodeSingleFrame || decodeSingleFrame && singleFrameDecoded) || parents.size() == 0 && !ignoreNoParent || generatingCache) { return; } long ms = 0; @@ -698,7 +712,11 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, ms = Math.min(invalidateAfter, Math.max(0, invalidateAfter - (System.currentTimeMillis() - lastFrameDecodeTime))); } if (useSharedQueue) { - executor.schedule(loadFrameTask = loadFrameRunnable, ms, TimeUnit.MILLISECONDS); + if (limitFps) { + DispatchQueuePoolBackground.execute(loadFrameTask = loadFrameRunnable); + } else { + executor.schedule(loadFrameTask = loadFrameRunnable, ms, TimeUnit.MILLISECONDS); + } } else { if (decodeQueue == null) { decodeQueue = new DispatchQueue("decodeQueue" + this); @@ -751,22 +769,22 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, @Override public void draw(Canvas canvas) { - drawInternal(canvas, false, System.currentTimeMillis()); + drawInternal(canvas, false, System.currentTimeMillis(), 0); } - public void drawInBackground(Canvas canvas, float x, float y, float w, float h, int alpha, ColorFilter colorFilter) { - if (dstRectBackground == null) { - dstRectBackground = new RectF(); - backgroundPaint = new Paint(); - backgroundPaint.setFilterBitmap(true); + public void drawInBackground(Canvas canvas, float x, float y, float w, float h, int alpha, ColorFilter colorFilter, int threadIndex) { + if (dstRectBackground[threadIndex] == null) { + dstRectBackground[threadIndex] = new RectF(); + backgroundPaint[threadIndex] = new Paint(); + backgroundPaint[threadIndex].setFilterBitmap(true); } - backgroundPaint.setAlpha(alpha); - backgroundPaint.setColorFilter(colorFilter); - dstRectBackground.set(x, y, x + w, y + h); - drawInternal(canvas, true, 0); + backgroundPaint[threadIndex].setAlpha(alpha); + backgroundPaint[threadIndex].setColorFilter(colorFilter); + dstRectBackground[threadIndex].set(x, y, x + w, y + h); + drawInternal(canvas, true, 0, threadIndex); } - public void drawInternal(Canvas canvas, boolean drawInBackground, long currentTime) { + public void drawInternal(Canvas canvas, boolean drawInBackground, long currentTime, int threadIndex) { if (!canLoadFrames() || destroyWhenDone) { return; } @@ -775,8 +793,8 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, currentTime = System.currentTimeMillis(); } - RectF rect = drawInBackground ? dstRectBackground : dstRect; - Paint paint = drawInBackground ? backgroundPaint : getPaint(); + RectF rect = drawInBackground ? dstRectBackground[threadIndex] : dstRect; + Paint paint = drawInBackground ? backgroundPaint[threadIndex] : getPaint(); if (!drawInBackground) { updateCurrentFrame(currentTime, false); @@ -809,36 +827,47 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, applyTransformation = false; } if (hasRoundRadius()) { - if (renderingShader == null) { - renderingShader = new BitmapShader(renderingBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + int index = drawInBackground ? threadIndex + 1 : 0; + if (renderingShader[index] == null) { + renderingShader[index] = new BitmapShader(renderingBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); } - paint.setShader(renderingShader); - shaderMatrix.reset(); - shaderMatrix.setTranslate(rect.left, rect.top); + paint.setShader(renderingShader[index]); + Matrix matrix = shaderMatrix[index]; + if (matrix == null) { + matrix = shaderMatrix[index] = new Matrix(); + } + Path path = roundPath[index]; + if (path == null) { + path = roundPath[index] = new Path(); + } + matrix.reset(); + matrix.setTranslate(rect.left, rect.top); if (metaData[2] == 90) { - shaderMatrix.preRotate(90); - shaderMatrix.preTranslate(0, -rect.width()); + matrix.preRotate(90); + matrix.preTranslate(0, -rect.width()); } else if (metaData[2] == 180) { - shaderMatrix.preRotate(180); - shaderMatrix.preTranslate(-rect.width(), -rect.height()); + matrix.preRotate(180); + matrix.preTranslate(-rect.width(), -rect.height()); } else if (metaData[2] == 270) { - shaderMatrix.preRotate(270); - shaderMatrix.preTranslate(-rect.height(), 0); + matrix.preRotate(270); + matrix.preTranslate(-rect.height(), 0); } - shaderMatrix.preScale(scaleX, scaleY); + matrix.preScale(scaleX, scaleY); - renderingShader.setLocalMatrix(shaderMatrix); - if (invalidatePath) { - invalidatePath = false; + renderingShader[index].setLocalMatrix(matrix); + if (invalidatePath || drawInBackground) { + if (!drawInBackground) { + invalidatePath = false; + } for (int a = 0; a < roundRadius.length; a++) { radii[a * 2] = roundRadius[a]; radii[a * 2 + 1] = roundRadius[a]; } - roundPath.reset(); - roundPath.addRoundRect(drawInBackground ? rect : actualDrawRect, radii, Path.Direction.CW); - roundPath.close(); + path.reset(); + path.addRoundRect(drawInBackground ? rect : actualDrawRect, radii, Path.Direction.CW); + path.close(); } - canvas.drawPath(roundPath, paint); + canvas.drawPath(path, paint); } else { canvas.translate(rect.left, rect.top); if (metaData[2] == 90) { @@ -1086,28 +1115,43 @@ public class AnimatedFileDrawable extends BitmapDrawable implements Animatable, if (renderingBitmap == null && nextRenderingBitmap == null) { scheduleNextGetFrame(); } else if (nextRenderingBitmap != null && (renderingBitmap == null || (Math.abs(now - lastFrameTime) >= invalidateAfter && !skipFrameUpdate))) { - if (precache) { + //if (precache) { backgroundBitmap = renderingBitmap; - } + // } renderingBitmap = nextRenderingBitmap; renderingBitmapTime = nextRenderingBitmapTime; - renderingShader = nextRenderingShader; + for (int i = 0; i < backgroundShader.length; i++) { + // if (precache) { + backgroundShader[i] = renderingShader[i]; + // } + renderingShader[i] = nextRenderingShader[i]; + nextRenderingShader[i] = null; + } nextRenderingBitmap = null; nextRenderingBitmapTime = 0; - nextRenderingShader = null; + lastFrameTime = now; + scheduleNextGetFrame(); + } else { + invalidateInternal(); } } else if (!isRunning && decodeSingleFrame && Math.abs(now - lastFrameTime) >= invalidateAfter && nextRenderingBitmap != null) { - if (precache) { + // if (precache) { backgroundBitmap = renderingBitmap; - } + // } renderingBitmap = nextRenderingBitmap; renderingBitmapTime = nextRenderingBitmapTime; - renderingShader = nextRenderingShader; + for (int i = 0; i < backgroundShader.length; i++) { + // if (precache) { + backgroundShader[i] = renderingShader[i]; + // } + renderingShader[i] = nextRenderingShader[i]; + nextRenderingShader[i] = null; + } nextRenderingBitmap = null; nextRenderingBitmapTime = 0; - nextRenderingShader = null; lastFrameTime = now; + scheduleNextGetFrame(); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index 9c8d14ee9..89b9e58e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -50,6 +50,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.content.FileProvider; +import androidx.core.graphics.ColorUtils; +import androidx.dynamicanimation.animation.FloatValueHolder; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -139,6 +143,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. private ActionBarMenuItem searchItem; private boolean blurredAnimationInProgress; private View[] buttons = new View[5]; + private SpringAnimation seekBarBufferSpring; private boolean draggingSeekBar; @@ -175,6 +180,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. long lastRewindingTime; long lastUpdateRewindingPlayerTime; + private boolean wasLight; + private final static int menu_speed_slow = 1; private final static int menu_speed_normal = 2; private final static int menu_speed_fast = 3; @@ -273,18 +280,15 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. lastMeasturedHeight = totalHeight; } ignoreLayout = true; - if (Build.VERSION.SDK_INT >= 21 && !isFullscreen) { - setPadding(backgroundPaddingLeft, AndroidUtilities.statusBarHeight, backgroundPaddingLeft, 0); - } playerLayout.setVisibility(searchWas || keyboardVisible ? INVISIBLE : VISIBLE); playerShadow.setVisibility(playerLayout.getVisibility()); int availableHeight = totalHeight - getPaddingTop(); LayoutParams layoutParams = (LayoutParams) listView.getLayoutParams(); - layoutParams.topMargin = ActionBar.getCurrentActionBarHeight(); + layoutParams.topMargin = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight; layoutParams = (LayoutParams) actionBarShadow.getLayoutParams(); - layoutParams.topMargin = ActionBar.getCurrentActionBarHeight(); + layoutParams.topMargin = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight; layoutParams = (LayoutParams) blurredView.getLayoutParams(); layoutParams.topMargin = -getPaddingTop(); @@ -397,11 +401,6 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. Theme.dialogs_onlineCirclePaint.setAlpha((int) (alpha * alphaProgress * rad)); canvas.drawRoundRect(rect, AndroidUtilities.dp(2), AndroidUtilities.dp(2), Theme.dialogs_onlineCirclePaint); } - - int color1 = getThemedColor(Theme.key_dialogBackground); - int finalColor = Color.argb((int) (255 * actionBar.getAlpha()), (int) (Color.red(color1) * 0.8f), (int) (Color.green(color1) * 0.8f), (int) (Color.blue(color1) * 0.8f)); - Theme.dialogs_onlineCirclePaint.setColor(finalColor); - canvas.drawRect(backgroundPaddingLeft, 0, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight, Theme.dialogs_onlineCirclePaint); } } @@ -439,7 +438,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. actionBar.setTitleColor(getThemedColor(Theme.key_player_actionBarTitle)); actionBar.setTitle(LocaleController.getString("AttachMusic", R.string.AttachMusic)); actionBar.setSubtitleColor(getThemedColor(Theme.key_player_actionBarSubtitle)); - actionBar.setOccupyStatusBar(false); + actionBar.setOccupyStatusBar(true); actionBar.setAlpha(0.0f); if (messageObject != null && !MediaController.getInstance().currentPlaylistIsGlobalSearch()) { @@ -648,6 +647,12 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. seekBarView.setReportChanges(true); playerLayout.addView(seekBarView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 5, 70, 5, 0)); + seekBarBufferSpring = new SpringAnimation(new FloatValueHolder(0)) + .setSpring(new SpringForce() + .setStiffness(750f) + .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)) + .addUpdateListener((animation, value, velocity) -> seekBarView.setBufferedProgress(value / 1000f)); + progressView = new LineProgressView(context); progressView.setVisibility(View.INVISIBLE); progressView.setBackgroundColor(getThemedColor(Theme.key_player_progressBackground)); @@ -1656,7 +1661,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } } if (bufferedProgress != -1) { - seekBarView.setBufferedProgress(bufferedProgress); + seekBarBufferSpring.getSpring().setFinalPosition(bufferedProgress * 1000); + seekBarBufferSpring.start(); } } } @@ -1706,11 +1712,30 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. actionBarAnimation.start(); } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); - newOffset += layoutParams.topMargin - AndroidUtilities.dp(11); + newOffset += layoutParams.topMargin - AndroidUtilities.statusBarHeight - AndroidUtilities.dp(11); if (scrollOffsetY != newOffset) { - listView.setTopGlowOffset((scrollOffsetY = newOffset) - layoutParams.topMargin); + listView.setTopGlowOffset((scrollOffsetY = newOffset) - layoutParams.topMargin - AndroidUtilities.statusBarHeight); containerView.invalidate(); } + + int offset = AndroidUtilities.dp(13); + top = scrollOffsetY - backgroundPaddingTop - offset; + if (currentSheetAnimationType == 1) { + top += listView.getTranslationY(); + } + float rad = 1.0f; + + if (top + backgroundPaddingTop < ActionBar.getCurrentActionBarHeight()) { + float toMove = offset + AndroidUtilities.dp(11 - 7); + float moveProgress = Math.min(1.0f, (ActionBar.getCurrentActionBarHeight() - top - backgroundPaddingTop) / toMove); + + rad = 1.0f - moveProgress; + } + + boolean light = rad <= 0.5f && ColorUtils.calculateLuminance(getThemedColor(Theme.key_dialogBackground)) > 0.7f; + if (light != wasLight) { + AndroidUtilities.setLightStatusBar(getWindow(), wasLight = light); + } } @Override @@ -1841,7 +1866,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } } if (bufferedProgress != -1) { - seekBarView.setBufferedProgress(bufferedProgress); + seekBarBufferSpring.getSpring().setFinalPosition(bufferedProgress * 1000); + seekBarBufferSpring.start(); } if (updateRewinding) { newTime = (int) (messageObject.getDuration() * seekBarView.getProgress()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java index d06e70a52..f8385856e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -10,9 +10,11 @@ package org.telegram.ui.Components; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.os.Build; import android.text.Layout; @@ -32,7 +34,8 @@ import org.telegram.ui.ActionBar.Theme; public class AvatarDrawable extends Drawable { private TextPaint namePaint; - private int color; + private boolean hasGradient; + private int color, color2; private boolean needApplyColorAccent; private StaticLayout textLayout; private float textWidth; @@ -46,6 +49,14 @@ public class AvatarDrawable extends Drawable { private StringBuilder stringBuilder = new StringBuilder(5); private int roundRadius = -1; + private int gradientTop, gradientBottom; + private int gradientColor1, gradientColor2; + private LinearGradient gradient; + + private int gradientTop2, gradientBottom2; + private int gradientColor21, gradientColor22; + private LinearGradient gradient2; + public static final int AVATAR_TYPE_NORMAL = 0; public static final int AVATAR_TYPE_SAVED = 1; public static final int AVATAR_TYPE_ARCHIVED = 2; @@ -106,7 +117,7 @@ public class AvatarDrawable extends Drawable { isProfile = value; } - private static int getColorIndex(long id) { + public static int getColorIndex(long id) { if (id >= 0 && id < 7) { return (int) id; } @@ -165,33 +176,55 @@ public class AvatarDrawable extends Drawable { public void setAvatarType(int value) { avatarType = value; if (avatarType == AVATAR_TYPE_REGISTER) { - color = Theme.getColor(Theme.key_chats_actionBackground); + hasGradient = false; + color = color2 = Theme.getColor(Theme.key_chats_actionBackground); } else if (avatarType == AVATAR_TYPE_ARCHIVED) { - color = getThemedColor(Theme.key_avatar_backgroundArchivedHidden); + hasGradient = false; + color = color2 = getThemedColor(Theme.key_avatar_backgroundArchivedHidden); } else if (avatarType == AVATAR_TYPE_REPLIES) { + hasGradient = true; color = getThemedColor(Theme.key_avatar_backgroundSaved); + color2 = getThemedColor(Theme.key_avatar_background2Saved); } else if (avatarType == AVATAR_TYPE_SAVED) { + hasGradient = true; color = getThemedColor(Theme.key_avatar_backgroundSaved); + color2 = getThemedColor(Theme.key_avatar_background2Saved); } else if (avatarType == AVATAR_TYPE_SHARES) { + hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(5)]); + } else if (avatarType == AVATAR_TYPE_FILTER_CONTACTS) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(5)]); + } else if (avatarType == AVATAR_TYPE_FILTER_NON_CONTACTS) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(4)]); + } else if (avatarType == AVATAR_TYPE_FILTER_GROUPS) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(3)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(3)]); + } else if (avatarType == AVATAR_TYPE_FILTER_CHANNELS) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(1)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(1)]); + } else if (avatarType == AVATAR_TYPE_FILTER_BOTS) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(0)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(0)]); + } else if (avatarType == AVATAR_TYPE_FILTER_MUTED) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(6)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(6)]); + } else if (avatarType == AVATAR_TYPE_FILTER_READ) { + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(5)]); } else { - if (avatarType == AVATAR_TYPE_FILTER_CONTACTS) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); - } else if (avatarType == AVATAR_TYPE_FILTER_NON_CONTACTS) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); - } else if (avatarType == AVATAR_TYPE_FILTER_GROUPS) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(3)]); - } else if (avatarType == AVATAR_TYPE_FILTER_CHANNELS) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(1)]); - } else if (avatarType == AVATAR_TYPE_FILTER_BOTS) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(0)]); - } else if (avatarType == AVATAR_TYPE_FILTER_MUTED) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(6)]); - } else if (avatarType == AVATAR_TYPE_FILTER_READ) { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(5)]); - } else { - color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); - } + hasGradient = true; + color = getThemedColor(Theme.keys_avatar_background[getColorIndex(4)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(4)]); } needApplyColorAccent = avatarType != AVATAR_TYPE_ARCHIVED && avatarType != AVATAR_TYPE_SAVED && avatarType != AVATAR_TYPE_REPLIES; } @@ -216,7 +249,15 @@ public class AvatarDrawable extends Drawable { } public void setColor(int value) { + hasGradient = false; + color = color2 = value; + needApplyColorAccent = false; + } + + public void setColor(int value, int value2) { + hasGradient = true; color = value; + color2 = value2; needApplyColorAccent = false; } @@ -232,8 +273,42 @@ public class AvatarDrawable extends Drawable { return needApplyColorAccent ? Theme.changeColorAccent(color) : color; } + public int getColor2() { + return needApplyColorAccent ? Theme.changeColorAccent(color2) : color2; + } + + private String takeFirstCharacter(String text) { + StringBuilder sequence = new StringBuilder(16); + boolean isInJoin = false; + int codePoint; + for (int i = 0; i < text.length(); i = text.offsetByCodePoints(i, 1)) { + codePoint = text.codePointAt(i); + if (codePoint == 0x200D || codePoint == 0x1f1ea) { + isInJoin = true; + if (sequence.length() == 0) + continue; + } else { + if ((sequence.length() > 0) && (!isInJoin)) + break; + isInJoin = false; + } + sequence.appendCodePoint(codePoint); + } + if (isInJoin) { + for (int i = sequence.length()-1; i >= 0; --i) { + if (sequence.charAt(i) == 0x200D) + sequence.deleteCharAt(i); + else + break; + } + } + return sequence.toString(); + } + public void setInfo(long id, String firstName, String lastName, String custom) { + hasGradient = true; color = getThemedColor(Theme.keys_avatar_background[getColorIndex(id)]); + color2 = getThemedColor(Theme.keys_avatar_background2[getColorIndex(id)]); needApplyColorAccent = id == 5; // Tinting manually set blue color avatarType = AVATAR_TYPE_NORMAL; @@ -249,28 +324,27 @@ public class AvatarDrawable extends Drawable { stringBuilder.append(custom); } else { if (firstName != null && firstName.length() > 0) { - stringBuilder.appendCodePoint(firstName.codePointAt(0)); + stringBuilder.append(takeFirstCharacter(firstName)); } if (lastName != null && lastName.length() > 0) { - Integer lastch = null; - for (int a = lastName.length() - 1; a >= 0; a--) { - if (lastch != null && lastName.charAt(a) == ' ') { - break; - } - lastch = lastName.codePointAt(a); + String lastNameLastWord = lastName; + int index; + if ((index = lastNameLastWord.lastIndexOf(' ')) >= 0) { + lastNameLastWord = lastNameLastWord.substring(index + 1); } if (Build.VERSION.SDK_INT > 17) { stringBuilder.append("\u200C"); } - stringBuilder.appendCodePoint(lastch); + stringBuilder.append(takeFirstCharacter(lastNameLastWord)); } else if (firstName != null && firstName.length() > 0) { for (int a = firstName.length() - 1; a >= 0; a--) { if (firstName.charAt(a) == ' ') { if (a != firstName.length() - 1 && firstName.charAt(a + 1) != ' ') { + int index = stringBuilder.length(); if (Build.VERSION.SDK_INT > 17) { stringBuilder.append("\u200C"); } - stringBuilder.appendCodePoint(firstName.codePointAt(a + 1)); + stringBuilder.append(takeFirstCharacter(firstName.substring(index))); break; } } @@ -304,7 +378,17 @@ public class AvatarDrawable extends Drawable { } int size = bounds.width(); namePaint.setColor(ColorUtils.setAlphaComponent(getThemedColor(Theme.key_avatar_text), alpha)); - Theme.avatar_backgroundPaint.setColor(ColorUtils.setAlphaComponent(getColor(), alpha)); + if (hasGradient) { + int color = ColorUtils.setAlphaComponent(getColor(), alpha); + int color2 = ColorUtils.setAlphaComponent(getColor2(), alpha); + if (gradient == null || gradientBottom != bounds.height() || gradientColor1 != color || gradientColor2 != color2) { + gradient = new LinearGradient(0, 0, 0, gradientBottom = bounds.height(), gradientColor1 = color, gradientColor2 = color2, Shader.TileMode.CLAMP); + } + Theme.avatar_backgroundPaint.setShader(gradient); + } else { + Theme.avatar_backgroundPaint.setShader(null); + Theme.avatar_backgroundPaint.setColor(ColorUtils.setAlphaComponent(getColor(), alpha)); + } canvas.save(); canvas.translate(bounds.left, bounds.top); if (roundRadius > 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDarawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDarawable.java rename to TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java index 53d5f76d8..8be264fa8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDarawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsDrawable.java @@ -30,7 +30,7 @@ import org.telegram.ui.Cells.GroupCallUserCell; import java.util.Random; -public class AvatarsDarawable { +public class AvatarsDrawable { public final static int STYLE_GROUP_CALL_TOOLTIP = 10; public final static int STYLE_MESSAGE_SEEN = 11; @@ -198,9 +198,9 @@ public class AvatarsDarawable { overrideSize = size; } - public void animateFromState(AvatarsDarawable avatarsDarawable, int currentAccount, boolean createAnimator) { - if (avatarsDarawable.transitionProgressAnimator != null) { - avatarsDarawable.transitionProgressAnimator.cancel(); + public void animateFromState(AvatarsDrawable avatarsDrawable, int currentAccount, boolean createAnimator) { + if (avatarsDrawable.transitionProgressAnimator != null) { + avatarsDrawable.transitionProgressAnimator.cancel(); if (transitionInProgress) { transitionInProgress = false; swapStates(); @@ -209,7 +209,7 @@ public class AvatarsDarawable { TLObject[] objects = new TLObject[3]; for (int i = 0; i < 3; i++) { objects[i] = currentStates[i].object; - setObject(i, currentAccount, avatarsDarawable.currentStates[i].object); + setObject(i, currentAccount, avatarsDrawable.currentStates[i].object); } commitTransition(false); for (int i = 0; i < 3; i++) { @@ -246,7 +246,7 @@ public class AvatarsDarawable { Random random = new Random(); - public AvatarsDarawable(View parent, boolean inCall) { + public AvatarsDrawable(View parent, boolean inCall) { this.parent = parent; for (int a = 0; a < 3; a++) { currentStates[a] = new DrawingState(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java index d3208fa0d..962b4b86b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarsImageView.java @@ -10,72 +10,72 @@ import org.telegram.tgnet.TLObject; public class AvatarsImageView extends View { - public final AvatarsDarawable avatarsDarawable; + public final AvatarsDrawable avatarsDrawable; public AvatarsImageView(@NonNull Context context, boolean inCall) { super(context); - avatarsDarawable = new AvatarsDarawable(this, inCall); + avatarsDrawable = new AvatarsDrawable(this, inCall); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - avatarsDarawable.width = getMeasuredWidth(); - avatarsDarawable.height = getMeasuredHeight(); + avatarsDrawable.width = getMeasuredWidth(); + avatarsDrawable.height = getMeasuredHeight(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - avatarsDarawable.onAttachedToWindow(); + avatarsDrawable.onAttachedToWindow(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - avatarsDarawable.onDraw(canvas); + avatarsDrawable.onDraw(canvas); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - avatarsDarawable.onDetachedFromWindow(); + avatarsDrawable.onDetachedFromWindow(); } public void setStyle(int style) { - avatarsDarawable.setStyle(style); + avatarsDrawable.setStyle(style); } public void setDelegate(Runnable delegate) { - avatarsDarawable.setDelegate(delegate); + avatarsDrawable.setDelegate(delegate); } public void setObject(int a, int currentAccount, TLObject object) { - avatarsDarawable.setObject(a, currentAccount, object); + avatarsDrawable.setObject(a, currentAccount, object); } public void setAvatarsTextSize(int size) { - avatarsDarawable.setAvatarsTextSize(size); + avatarsDrawable.setAvatarsTextSize(size); } public void reset() { - avatarsDarawable.reset(); + avatarsDrawable.reset(); } public void setCount(int usersCount) { - avatarsDarawable.setCount(usersCount); + avatarsDrawable.setCount(usersCount); } public void commitTransition(boolean animated) { - avatarsDarawable.commitTransition(animated); + avatarsDrawable.commitTransition(animated); } public void updateAfterTransitionEnd() { - avatarsDarawable.updateAfterTransitionEnd(); + avatarsDrawable.updateAfterTransitionEnd(); } public void setCentered(boolean centered) { - avatarsDarawable.setCentered(centered); + avatarsDrawable.setCentered(centered); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java index 52b919761..a54d9056e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BackButtonMenu.java @@ -1,6 +1,8 @@ package org.telegram.ui.Components; import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -12,9 +14,12 @@ import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.TextView; +import androidx.core.content.ContextCompat; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageLocation; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; @@ -23,7 +28,9 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.INavigationLayout; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.ProfileActivity; +import org.telegram.ui.TopicsFragment; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +48,7 @@ public class BackButtonMenu { int filterId; } - public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButton, long currentDialogId, Theme.ResourcesProvider resourcesProvider) { + public static ActionBarPopupWindow show(BaseFragment thisFragment, View backButton, long currentDialogId, int topicId, Theme.ResourcesProvider resourcesProvider) { if (thisFragment == null) { return null; } @@ -51,7 +58,14 @@ public class BackButtonMenu { if (parentLayout == null || context == null || fragmentView == null) { return null; } - ArrayList dialogs = getStackedHistoryDialogs(thisFragment, currentDialogId); + ArrayList dialogs; + if (topicId != 0) { + new ArrayList<>(); + dialogs = getStackedHistoryForTopic(thisFragment, currentDialogId, topicId); + } else { + dialogs = getStackedHistoryDialogs(thisFragment, currentDialogId); + } + if (dialogs.size() <= 0) { return null; } @@ -72,7 +86,11 @@ public class BackButtonMenu { cell.setMinimumWidth(AndroidUtilities.dp(200)); BackupImageView imageView = new BackupImageView(context); - imageView.setRoundRadius(AndroidUtilities.dp(32)); + if (chat == null && user == null) { + imageView.setRoundRadius(0); + } else { + imageView.setRoundRadius(chat != null && chat.forum ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16)); + } cell.addView(imageView, LayoutHelper.createFrameRelatively(32, 32, Gravity.START | Gravity.CENTER_VERTICAL, 13, 0, 0, 0)); TextView titleView = new TextView(context); @@ -85,6 +103,7 @@ public class BackButtonMenu { AvatarDrawable avatarDrawable = new AvatarDrawable(); avatarDrawable.setSmallSize(true); Drawable thumb = avatarDrawable; + boolean addDivider = false; if (chat != null) { avatarDrawable.setInfo(chat); if (chat.photo != null && chat.photo.strippedBitmap != null) { @@ -115,6 +134,13 @@ public class BackButtonMenu { imageView.setImage(ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL), "50_50", thumb, user); } titleView.setText(name); + } else { + Drawable drawable = ContextCompat.getDrawable(context, R.drawable.msg_viewchats).mutate(); + imageView.setImageDrawable(drawable); + imageView.setSize(AndroidUtilities.dp(24), AndroidUtilities.dp(24)); + imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon, resourcesProvider), PorterDuff.Mode.MULTIPLY)); + titleView.setText(LocaleController.getString("AllChats", R.string.AllChats)); + addDivider = true; } cell.setBackground(Theme.getSelectorDrawable(Theme.getColor(Theme.key_listSelector, resourcesProvider), false)); @@ -140,13 +166,12 @@ public class BackButtonMenu { } } else { if (parentLayout != null && parentLayout.getFragmentStack() != null) { - for (int j = parentLayout.getFragmentStack().size() - 2; j > pDialog.stackIndex; --j) { - if (j >= 0 && j < parentLayout.getFragmentStack().size()) { - parentLayout.removeFragmentFromStack(j); - } + ArrayList fragments = new ArrayList<>(parentLayout.getFragmentStack()); + for (int j = fragments.size() - 2; j > pDialog.stackIndex; --j) { + fragments.get(j).removeSelfFromStack(); } if (pDialog.stackIndex < parentLayout.getFragmentStack().size()) { - parentLayout.bringToFront(pDialog.stackIndex); + // parentLayout.bringToFront(pDialog.stackIndex); parentLayout.closeLastFragment(true); return; } @@ -156,6 +181,12 @@ public class BackButtonMenu { goToPulledDialog(thisFragment, pDialog); }); layout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + if (addDivider) { + FrameLayout gap = new FrameLayout(context); + gap.setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuSeparator, resourcesProvider)); + gap.setTag(R.id.fit_width_tag, 1); + layout.addView(gap, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 8)); + } } ActionBarPopupWindow scrimPopupWindow = new ActionBarPopupWindow(layout, LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT); @@ -188,6 +219,30 @@ public class BackButtonMenu { return scrimPopupWindow; } + private static ArrayList getStackedHistoryForTopic(BaseFragment thisFragment, long currentDialogId, int topicId) { + ArrayList dialogs = new ArrayList<>(); + if (thisFragment.getParentLayout().getFragmentStack().size() > 1 && thisFragment.getParentLayout().getFragmentStack().get(thisFragment.getParentLayout().getFragmentStack().size() - 2) instanceof TopicsFragment) { + PulledDialog pulledDialog = new PulledDialog(); + dialogs.add(pulledDialog); + pulledDialog.stackIndex = 0; + pulledDialog.activity = DialogsActivity.class; + + pulledDialog = new PulledDialog(); + dialogs.add(pulledDialog); + pulledDialog.stackIndex = thisFragment.getParentLayout().getFragmentStack().size() - 2; + pulledDialog.activity = TopicsFragment.class; + pulledDialog.chat = MessagesController.getInstance(thisFragment.getCurrentAccount()).getChat(-currentDialogId); + return dialogs; + } else { + PulledDialog pulledDialog = new PulledDialog(); + dialogs.add(pulledDialog); + pulledDialog.stackIndex = -1; + pulledDialog.activity = TopicsFragment.class; + pulledDialog.chat = MessagesController.getInstance(thisFragment.getCurrentAccount()).getChat(-currentDialogId); + return dialogs; + } + } + public static void goToPulledDialog(BaseFragment fragment, PulledDialog dialog) { if (dialog == null) { return; @@ -206,6 +261,13 @@ public class BackButtonMenu { Bundle bundle = new Bundle(); bundle.putLong("dialog_id", dialog.dialogId); fragment.presentFragment(new ProfileActivity(bundle), true); + } if (dialog.activity == TopicsFragment.class) { + Bundle bundle = new Bundle(); + bundle.putLong("chat_id", dialog.chat.id); + fragment.presentFragment(new TopicsFragment(bundle), true); + } if (dialog.activity == DialogsActivity.class) { + + fragment.presentFragment(new DialogsActivity(null), true); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index 9fe7db70f..aee67a41e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -1271,7 +1271,7 @@ public class Bulletin { super(context, resourcesProvider); avatarsImageView = new AvatarsImageView(context, false); - avatarsImageView.setStyle(AvatarsDarawable.STYLE_MESSAGE_SEEN); + avatarsImageView.setStyle(AvatarsDrawable.STYLE_MESSAGE_SEEN); addView(avatarsImageView, LayoutHelper.createFrameRelatively(24 + 12 + 12 + 8, 48, Gravity.START | Gravity.CENTER_VERTICAL, 12, 0, 0, 0)); textView = new LinkSpanDrawable.LinksTextView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java new file mode 100644 index 000000000..e01258d42 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CanvasButton.java @@ -0,0 +1,218 @@ +package org.telegram.ui.Components; + +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.CornerPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; +import android.os.Build; +import android.util.StateSet; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewConfiguration; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; + +import java.util.ArrayList; + +public class CanvasButton { + + Path drawingPath = new Path(); + ArrayList drawingRects = new ArrayList<>(); + int usingRectCount; + boolean buttonPressed; + RippleDrawable selectorDrawable; + private final static int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + + private final View parent; + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Runnable delegate; + private boolean pathCreated; + Runnable longPressRunnable; + Runnable longPressRunnableInner = new Runnable() { + @Override + public void run() { + checkTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0, 0, 0)); + parent.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + if (longPressRunnable != null) { + longPressRunnable.run(); + } + } + }; + private boolean longPressEnabled; + + public CanvasButton(View parent) { + this.parent = parent; + paint.setPathEffect(new CornerPathEffect(AndroidUtilities.dp(12))); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + final Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + maskPaint.setFilterBitmap(true); + maskPaint.setPathEffect(new CornerPathEffect(AndroidUtilities.dp(12))); + maskPaint.setColor(0xffffffff); + Drawable maskDrawable = new Drawable() { + + @Override + public void draw(Canvas canvas) { + drawInternal(canvas, maskPaint); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + }; + ColorStateList colorStateList = new ColorStateList( + new int[][]{StateSet.WILD_CARD}, + new int[]{Theme.getColor(Theme.key_listSelector) & 0x19ffffff} + ); + selectorDrawable = new RippleDrawable(colorStateList, null, maskDrawable); + } + } + + + public void draw(Canvas canvas) { + drawInternal(canvas, paint); + if (selectorDrawable != null) { + selectorDrawable.draw(canvas); + } + } + + private void drawInternal(Canvas canvas, Paint paint) { + if (usingRectCount > 1) { + if (!pathCreated) { + drawingPath.rewind(); + int left = 0, top = 0, right = 0, bottom = 0; + for (int i = 0; i < usingRectCount; i++) { + if (i + 1 < usingRectCount) { + float rightCurrent = drawingRects.get(i).right; + float rightNext = drawingRects.get(i + 1).right; + if (Math.abs(rightCurrent - rightNext) < AndroidUtilities.dp(4)) { + drawingRects.get(i + 1).right = drawingRects.get(i).right = Math.max(rightCurrent, rightNext); + } + } + if (i == 0 || drawingRects.get(i).bottom > bottom) { + bottom = (int) drawingRects.get(i).bottom; + } + if (i == 0 || drawingRects.get(i).right > right) { + right = (int) drawingRects.get(i).right; + } + if (i == 0 || drawingRects.get(i).left < left) { + left = (int) drawingRects.get(i).left; + } + if (i == 0 || drawingRects.get(i).top < top) { + top = (int) drawingRects.get(i).top; + } + drawingPath.addRect(drawingRects.get(i), Path.Direction.CCW); + if (selectorDrawable != null) { + selectorDrawable.setBounds(left, top, right, bottom); + } + } + pathCreated = true; + } + canvas.drawPath(drawingPath, paint); + } else if (usingRectCount == 1) { + canvas.drawRoundRect(drawingRects.get(0), AndroidUtilities.dp(10), AndroidUtilities.dp(10), paint); + } + } + + public boolean checkTouchEvent(MotionEvent event) { + int x = (int) event.getX(); + int y = (int) event.getY(); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (contains(x, y)) { + buttonPressed = true; + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable != null) { + selectorDrawable.setHotspot(x, y); + selectorDrawable.setState(pressedState); + } + AndroidUtilities.cancelRunOnUIThread(longPressRunnableInner); + if (longPressEnabled) { + AndroidUtilities.runOnUIThread(longPressRunnableInner, ViewConfiguration.getLongPressTimeout()); + } + parent.invalidate(); + return true; + } + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (buttonPressed) { + if (event.getAction() == MotionEvent.ACTION_UP && delegate != null) { + delegate.run(); + } + parent.playSoundEffect(SoundEffectConstants.CLICK); + if (Build.VERSION.SDK_INT >= 21 && selectorDrawable != null) { + selectorDrawable.setState(StateSet.NOTHING); + } + buttonPressed = false; + parent.invalidate(); + } + AndroidUtilities.cancelRunOnUIThread(longPressRunnableInner); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (buttonPressed && Build.VERSION.SDK_INT >= 21 && selectorDrawable != null) { + selectorDrawable.setHotspot(x, y); + } + } + return buttonPressed; + } + + private boolean contains(int x, int y) { + for (int i = 0; i < usingRectCount; i++) { + if (drawingRects.get(i).contains(x, y)) { + return true; + } + } + return false; + } + + public void setColor(int color) { + paint.setColor(color); + if (selectorDrawable != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Theme.setSelectorDrawableColor(selectorDrawable, color, true); + } + } + + public void setDelegate(Runnable delegate) { + this.delegate = delegate; + } + + public void rewind() { + pathCreated = false; + usingRectCount = 0; + } + + public void addRect(RectF rectF) { + usingRectCount++; + if (usingRectCount > drawingRects.size()) { + drawingRects.add(new RectF()); + } + RectF rect = drawingRects.get(usingRectCount - 1); + rect.set(rectF); + } + + public void setRect(RectF rectF) { + rewind(); + addRect(rectF); + } + + public void setLongPress(Runnable runnable) { + longPressEnabled = true; + longPressRunnable = runnable; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java new file mode 100644 index 000000000..cba1817be --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityInterface.java @@ -0,0 +1,52 @@ +package org.telegram.ui.Components; + +import org.telegram.messenger.ChatObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; + +public interface ChatActivityInterface { + + default ChatObject.Call getGroupCall() { + return null; + } + + default TLRPC.Chat getCurrentChat() { + return null; + } + + default TLRPC.User getCurrentUser() { + return null; + } + + long getDialogId(); + + default void scrollToMessageId(int id, int i, boolean b, int i1, boolean b1, int i2) { + + } + + default boolean shouldShowImport() { + return false; + } + + default boolean openedWithLivestream() { + return false; + } + + default long getMergeDialogId() { + return 0; + } + + default int getTopicId() { + return 0; + } + + ChatAvatarContainer getAvatarContainer(); + + default void checkAndUpdateAvatar() { + + } + + SizeNotifierFrameLayout getContentView(); + + ActionBar getActionBar(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index b5ff92e87..aa8c05907 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -723,6 +723,8 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent } setTypingAnimation(false); if (parentFragment.isTopic && chat != null) { + int count = parentFragment.getThreadMessage().getRepliesCount(); + // newSubtitle = LocaleController.formatPluralString("messages", count, count); newSubtitle = LocaleController.formatString("TopicProfileStatus", R.string.TopicProfileStatus, chat.title); } else if (chat != null) { TLRPC.ChatFull info = parentFragment.getCurrentChatInfo(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogsItemAnimator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogsItemAnimator.java index 1341d3dd4..d751f2009 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogsItemAnimator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DialogsItemAnimator.java @@ -62,6 +62,7 @@ public class DialogsItemAnimator extends SimpleItemAnimator { private final RecyclerListView listView; public DialogsItemAnimator(RecyclerListView listView) { + setSupportsChangeAnimations(false); this.listView = listView; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java index 82b63f5bb..65044138d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/DrawingInBackgroundThreadDrawable.java @@ -4,7 +4,6 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.util.Log; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; @@ -18,6 +17,7 @@ import java.util.ArrayList; public class DrawingInBackgroundThreadDrawable implements NotificationCenter.NotificationCenterDelegate { + public final static int THREAD_COUNT = 2; boolean attachedToWindow; Bitmap backgroundBitmap; @@ -26,9 +26,6 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not Bitmap bitmap; Canvas bitmapCanvas; - Bitmap nextRenderingBitmap; - Canvas nextRenderingCanvas; - private boolean bitmapUpdating; public int currentLayerNum = 1; @@ -42,10 +39,11 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not int width; int padding; - private static DispatchQueue backgroundQueue; + public static DispatchQueuePool queuePool; + private final DispatchQueue backgroundQueue; boolean error; - Runnable bitmapCreateTask = new Runnable() { + private final Runnable bitmapCreateTask = new Runnable() { @Override public void run() { try { @@ -74,6 +72,8 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not } }; + boolean needSwapBitmaps; + Runnable uiFrameRunnable = new Runnable() { @Override public void run() { @@ -89,26 +89,19 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not if (frameGuid != lastFrameId) { return; } - Bitmap bitmapTmp = bitmap; - Canvas bitmapCanvasTmp = bitmapCanvas; - - bitmap = nextRenderingBitmap; - bitmapCanvas = nextRenderingCanvas; - - nextRenderingBitmap = backgroundBitmap; - nextRenderingCanvas = backgroundCanvas; - - backgroundBitmap = bitmapTmp; - backgroundCanvas = bitmapCanvasTmp; + needSwapBitmaps = true; } }; private boolean reset; private int lastFrameId; + public final int threadIndex; public DrawingInBackgroundThreadDrawable() { - if (backgroundQueue == null) { - backgroundQueue = new DispatchQueue("draw_background_queue"); + if (queuePool == null) { + queuePool = new DispatchQueuePool(THREAD_COUNT); } + backgroundQueue = queuePool.getNextQueue(); + threadIndex = queuePool.pointer; } public void draw(Canvas canvas, long time, int w, int h, float alpha) { @@ -121,7 +114,19 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not height = h; width = w; - if ((bitmap == null && nextRenderingBitmap == null) || reset) { + if (needSwapBitmaps) { + needSwapBitmaps = false; + Bitmap bitmapTmp = bitmap; + Canvas bitmapCanvasTmp = bitmapCanvas; + + bitmap = backgroundBitmap; + bitmapCanvas = backgroundCanvas; + + backgroundBitmap = bitmapTmp; + backgroundCanvas = bitmapCanvasTmp; + } + + if (bitmap == null || reset) { reset = false; if (bitmap != null) { @@ -131,16 +136,16 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not bitmap = null; } int heightInternal = height + padding; - if (nextRenderingBitmap == null || nextRenderingBitmap.getHeight() != heightInternal || nextRenderingBitmap.getWidth() != width) { - nextRenderingBitmap = Bitmap.createBitmap(width, heightInternal, Bitmap.Config.ARGB_8888); - nextRenderingCanvas = new Canvas(nextRenderingBitmap); + if (bitmap == null || bitmap.getHeight() != heightInternal || bitmap.getWidth() != width) { + bitmap = Bitmap.createBitmap(width, heightInternal, Bitmap.Config.ARGB_8888); + bitmapCanvas = new Canvas(bitmap); } else { - nextRenderingBitmap.eraseColor(Color.TRANSPARENT); + bitmap.eraseColor(Color.TRANSPARENT); } - nextRenderingCanvas.save(); - nextRenderingCanvas.translate(0, padding); - drawInUiThread(nextRenderingCanvas, 1f); - nextRenderingCanvas.restore(); + bitmapCanvas.save(); + bitmapCanvas.translate(0, padding); + drawInUiThread(bitmapCanvas, 1f); + bitmapCanvas.restore(); } if (!bitmapUpdating && !paused) { @@ -150,11 +155,8 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not backgroundQueue.postRunnable(bitmapCreateTask); } - if (bitmap != null || nextRenderingBitmap != null) { + if (bitmap != null ) { Bitmap drawingBitmap = bitmap; - if (drawingBitmap == null) { - drawingBitmap = nextRenderingBitmap; - } paint.setAlpha((int) (255 * alpha)); canvas.save(); canvas.translate(0, -padding); @@ -202,11 +204,7 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not if (bitmap != null) { bitmaps.add(bitmap); } - if (nextRenderingBitmap != null) { - bitmaps.add(nextRenderingBitmap); - } bitmap = null; - nextRenderingBitmap = null; AndroidUtilities.recycleBitmaps(bitmaps); attachedToWindow = false; NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.stopAllHeavyOperations); @@ -261,4 +259,29 @@ public class DrawingInBackgroundThreadDrawable implements NotificationCenter.Not AndroidUtilities.recycleBitmaps(bitmaps); } } + + public static class DispatchQueuePool { + final int size; + int pointer; + + public final DispatchQueue[] pool; + + private DispatchQueuePool(int size) { + this.size = size; + pool = new DispatchQueue[size]; + } + + public DispatchQueue getNextQueue() { + pointer++; + if (pointer > size - 1) { + pointer = 0; + } + DispatchQueue queue = pool[pointer]; + if (queue == null) { + queue = pool[pointer] = new DispatchQueue("draw_background_queue_" + pointer); + } + return queue; + } + + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java index 3ec209b4c..19ee6713e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiPacksAlert.java @@ -312,11 +312,11 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } drawable.update(time); - imageView.backgroundThreadDrawHolder = drawable.getImageReceiver().setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder); - imageView.backgroundThreadDrawHolder.time = time; + imageView.backgroundThreadDrawHolder[threadIndex] = drawable.getImageReceiver().setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder[threadIndex], threadIndex); + imageView.backgroundThreadDrawHolder[threadIndex].time = time; drawable.setAlpha(255); AndroidUtilities.rectTmp2.set(imageView.getLeft() + imageView.getPaddingLeft(), imageView.getPaddingTop(), imageView.getRight() - imageView.getPaddingRight(), imageView.getMeasuredHeight() - imageView.getPaddingBottom()); - imageView.backgroundThreadDrawHolder.setBounds(AndroidUtilities.rectTmp2); + imageView.backgroundThreadDrawHolder[threadIndex].setBounds(AndroidUtilities.rectTmp2); imageView.imageReceiver = drawable.getImageReceiver(); drawInBackgroundViews.add(imageView); } @@ -350,7 +350,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N public void drawInBackground(Canvas canvas) { for (int i = 0; i < drawInBackgroundViews.size(); i++) { EmojiImageView imageView = drawInBackgroundViews.get(i); - imageView.imageReceiver.draw(canvas, imageView.backgroundThreadDrawHolder); + imageView.imageReceiver.draw(canvas, imageView.backgroundThreadDrawHolder[threadIndex]); } } @@ -394,7 +394,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N super.onFrameReady(); for (int i = 0; i < drawInBackgroundViews.size(); i++) { EmojiImageView imageView = drawInBackgroundViews.get(i); - imageView.backgroundThreadDrawHolder.release(); + imageView.backgroundThreadDrawHolder[threadIndex].release(); } containerView.invalidate(); } @@ -1138,7 +1138,7 @@ public class EmojiPacksAlert extends BottomSheet implements NotificationCenter.N } } private class EmojiImageView extends View { - public ImageReceiver.BackgroundThreadDrawHolder backgroundThreadDrawHolder; + public ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; public ImageReceiver imageReceiver; public EmojiImageView(Context context) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index c7e957196..f34e6011d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -21,7 +21,6 @@ import android.content.DialogInterface; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.ColorFilter; import android.graphics.DashPathEffect; import android.graphics.Outline; import android.graphics.Paint; @@ -932,7 +931,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private boolean isRecent; private AnimatedEmojiSpan span; private EmojiPack pack; - private ImageReceiver.BackgroundThreadDrawHolder backgroundThreadDrawHolder; + private ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; float pressedProgress; ValueAnimator backAnimator; @@ -2829,13 +2828,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } drawable.update(time); - imageView.backgroundThreadDrawHolder = drawable.getImageReceiver().setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder); - imageView.backgroundThreadDrawHolder.time = time; - imageView.backgroundThreadDrawHolder.overrideAlpha = 1f; + imageView.backgroundThreadDrawHolder[threadIndex] = drawable.getImageReceiver().setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder[threadIndex], threadIndex); + imageView.backgroundThreadDrawHolder[threadIndex].time = time; + imageView.backgroundThreadDrawHolder[threadIndex].overrideAlpha = 1f; drawable.setAlpha(255); int topOffset = (int) (imageView.getHeight() * .03f); AndroidUtilities.rectTmp2.set(imageView.getLeft() + imageView.getPaddingLeft() - startOffset, topOffset, imageView.getRight() - imageView.getPaddingRight() - startOffset, topOffset + imageView.getMeasuredHeight() - imageView.getPaddingTop() - imageView.getPaddingBottom()); - imageView.backgroundThreadDrawHolder.setBounds(AndroidUtilities.rectTmp2); + imageView.backgroundThreadDrawHolder[threadIndex].setBounds(AndroidUtilities.rectTmp2); imageView.drawable = drawable; imageView.imageReceiver = drawable.getImageReceiver(); drawInBackgroundViews.add(imageView); @@ -2847,7 +2846,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific for (int i = 0; i < drawInBackgroundViews.size(); i++) { ImageViewEmoji imageView = drawInBackgroundViews.get(i); if (imageView.drawable != null) { - imageView.drawable.draw(canvas, imageView.backgroundThreadDrawHolder, false); + imageView.drawable.draw(canvas, imageView.backgroundThreadDrawHolder[threadIndex], false); } } } @@ -2914,7 +2913,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific for (int i = 0; i < drawInBackgroundViews.size(); i++) { ImageViewEmoji imageView = drawInBackgroundViews.get(i); if (imageView.backgroundThreadDrawHolder != null) { - imageView.backgroundThreadDrawHolder.release(); + imageView.backgroundThreadDrawHolder[threadIndex].release(); } } emojiGridView.invalidate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java index e8a98f4e1..025ef1f15 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/ForumUtilities.java @@ -1,10 +1,10 @@ package org.telegram.ui.Components.Forum; +import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ImageSpan; @@ -71,6 +71,16 @@ public class ForumUtilities { return combinedDrawable; } + public static Drawable createSmallTopicDrawable(String text, int color) { + ForumBubbleDrawable forumBubbleDrawable = new ForumBubbleDrawable(color); + LetterDrawable letterDrawable = new LetterDrawable(null, LetterDrawable.STYLE_SMALL_TOPIC_DRAWABLE); + String title = text.trim().toUpperCase(); + letterDrawable.setTitle(title.length() >= 1 ? title.substring(0, 1) : ""); + CombinedDrawable combinedDrawable = new CombinedDrawable(forumBubbleDrawable, letterDrawable, 0, 0); + combinedDrawable.setFullsize(true); + return combinedDrawable; + } + public static void openTopic(BaseFragment baseFragment, long chatId, TLRPC.TL_forumTopic topic, int fromMessageId) { if (baseFragment == null || topic == null) { return; @@ -78,8 +88,12 @@ public class ForumUtilities { TLRPC.Chat chatLocal = baseFragment.getMessagesController().getChat(chatId); Bundle args = new Bundle(); args.putLong("chat_id", chatId); + if (fromMessageId != 0) { args.putInt("message_id", fromMessageId); + } else if (topic.read_inbox_max_id == 0) { + //scroll to first message in topic + args.putInt("message_id", topic.id); } args.putInt("unread_count", topic.unread_count); args.putBoolean("historyPreloaded", false); @@ -104,11 +118,11 @@ public class ForumUtilities { baseFragment.presentFragment(chatActivity); } - public static CharSequence getTopicSpannedName(TLRPC.ForumTopic topic, TextPaint paint) { + public static CharSequence getTopicSpannedName(TLRPC.ForumTopic topic, Paint paint) { return getTopicSpannedName(topic, paint, null); } - public static CharSequence getTopicSpannedName(TLRPC.ForumTopic topic, TextPaint paint, ForumBubbleDrawable[] drawableToSet) { + public static CharSequence getTopicSpannedName(TLRPC.ForumTopic topic, Paint paint, ForumBubbleDrawable[] drawableToSet) { SpannableStringBuilder sb = new SpannableStringBuilder(); if (topic instanceof TLRPC.TL_forumTopic) { TLRPC.TL_forumTopic forumTopic = (TLRPC.TL_forumTopic) topic; @@ -116,6 +130,7 @@ public class ForumUtilities { sb.append(" "); AnimatedEmojiSpan span; sb.setSpan(span = new AnimatedEmojiSpan(forumTopic.icon_emoji_id, .95f, paint == null ? null : paint.getFontMetricsInt()), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + span.top = true; span.cacheType = AnimatedEmojiDrawable.CACHE_TYPE_EMOJI_STATUS; } else { sb.append(" "); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java new file mode 100644 index 000000000..1a39f7177 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Forum/MessageTopicButton.java @@ -0,0 +1,434 @@ +package org.telegram.ui.Components.Forum; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextUtils; +import android.view.MotionEvent; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ChatMessageCell; +import org.telegram.ui.Components.AnimatedColor; +import org.telegram.ui.Components.AnimatedEmojiDrawable; +import org.telegram.ui.Components.StaticLayoutEx; + +public class MessageTopicButton { + + private final static float[] lightHueRanges = { 0, 43, 56, 86, 169, 183, 249, 289, 360 }; + private final static float[] lightSatValues = { .60f, 1f, .95f, .98f, .80f, .88f, .51f, .55f, .60f }; + private final static float[] lightValValues = { .79f, .77f, .60f, .62f, .60f, .61f, .80f, .70f, .79f }; + + private final static float[] darkHueRanges = { 0, 43, 56, 63, 86, 122, 147, 195, 205, 249, 270, 312, 388, 360 }; + private final static float[] darkSatValues = { .64f, .89f, .84f, .87f, .74f, .66f, .81f, .81f, .71f, .51f, .61f, .55f, .62f, .64f }; + private final static float[] darkValValues = { .92f, .90f, .82f, .82f, .84f, .84f, .82f, .88f, .96f, .100f, .93f, .88f, .96f, .92f }; + + private int topicWidth; + private int topicHeight; + private Paint topicPaint; + private Path topicPath; + private Drawable topicArrowDrawable; + private Drawable topicSelectorDrawable; + private Drawable topicIconDrawable; + private Rect topicIconDrawableBounds; + private float[] topicHSV; + private int topicBackgroundColor; + private int topicNameColor; + private int topicArrowColor; + private AnimatedColor topicBackgroundColorAnimated, topicNameColorAnimated; + private boolean topicIconWaiting; + private StaticLayout topicNameLayout; + private RectF topicHitRect; + private boolean topicPressed; + private MessageObject lastMessageObject; + + private Context context; + private Theme.ResourcesProvider resourcesProvider; + + private final static int[] idleState = new int[]{}; + private final static int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + + public MessageTopicButton(Context context, Theme.ResourcesProvider resourcesProvider) { + this.context = context; + this.resourcesProvider = resourcesProvider; + } + + protected void onClick() {} + + public int set(ChatMessageCell cell, MessageObject messageObject, TLRPC.TL_forumTopic topic, int maxWidth) { + lastMessageObject = messageObject; + if (cell == null || messageObject == null) { + return 0; + } + + int iconsz = AndroidUtilities.dp(7) + (int) Theme.chat_topicTextPaint.getTextSize(); + float padleft = AndroidUtilities.dp(10) + iconsz; + float padright1 = Theme.chat_topicTextPaint.getTextSize() - AndroidUtilities.dp(8); + float padright = AndroidUtilities.dp(5) + Theme.chat_topicTextPaint.getTextSize(); + maxWidth -= padleft + padright; + + String title = topic.title == null ? "" : topic.title; + topicNameLayout = StaticLayoutEx.createStaticLayout(title, 0, title.length(), Theme.chat_topicTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1f, 0, false, TextUtils.TruncateAt.END, maxWidth, 2, false); + topicHeight = AndroidUtilities.dp(4 + 4.5f) + Math.min(AndroidUtilities.dp(24), topicNameLayout == null ? 0 : topicNameLayout.getHeight()); + float textWidth = 0; + int lineCount = topicNameLayout == null ? 0 : topicNameLayout.getLineCount(); + if (topicPath == null) { + topicPath = new Path(); + } else { + topicPath.rewind(); + } + if (topicPaint == null) { + topicPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + int iconColor; + if (topic.icon_emoji_id != 0) { + if (!(topicIconDrawable instanceof AnimatedEmojiDrawable) || topic.icon_emoji_id != ((AnimatedEmojiDrawable) topicIconDrawable).getDocumentId()) { + if (topicIconDrawable instanceof AnimatedEmojiDrawable) { + ((AnimatedEmojiDrawable) topicIconDrawable).removeView(cell::invalidateOutbounds); + topicIconDrawable = null; + } + topicIconDrawable = AnimatedEmojiDrawable.make(messageObject.currentAccount, AnimatedEmojiDrawable.CACHE_TYPE_MESSAGES, topic.icon_emoji_id); + ((AnimatedEmojiDrawable) topicIconDrawable).addView(cell::invalidateOutbounds); + } + topicIconWaiting = false; + iconColor = topicIconDrawable instanceof AnimatedEmojiDrawable ? AnimatedEmojiDrawable.getDominantColor((AnimatedEmojiDrawable) topicIconDrawable) : 0; + if (iconColor == 0) { + topicIconWaiting = true; + iconColor = getThemedColor(messageObject.isOutOwner() ? Theme.key_chat_outReactionButtonText : Theme.key_chat_inReactionButtonText); + } + } else { + iconColor = topic.icon_color; + topicIconDrawable = ForumUtilities.createSmallTopicDrawable(title, topic.icon_color); + } + setupColors(iconColor); + if (topicIconWaiting) { + if (topicNameColorAnimated == null) { + topicNameColorAnimated = new AnimatedColor(cell); + } + if (topicBackgroundColorAnimated == null) { + topicBackgroundColorAnimated = new AnimatedColor(cell); + } + } + if (topicArrowDrawable == null && context != null) { + topicArrowDrawable = context.getResources().getDrawable(R.drawable.msg_mini_topicarrow).mutate(); + } + topicArrowDrawable.setColorFilter(new PorterDuffColorFilter(topicArrowColor = ColorUtils.setAlphaComponent(topicNameColor, 140), PorterDuff.Mode.MULTIPLY)); + + float R = (AndroidUtilities.dp(11) + (int) Theme.chat_topicTextPaint.getTextSize()); + int arrowsz = Math.max(1, (int) Theme.chat_topicTextPaint.getTextSize() + AndroidUtilities.dp(0)); + if (lineCount == 2) { + topicHeight = AndroidUtilities.dp(15) + 2 * ((int) Theme.chat_topicTextPaint.getTextSize()); + float l1w = topicNameLayout.getLineWidth(0) - topicNameLayout.getLineLeft(0); + float l2w = topicNameLayout.getLineWidth(1) - topicNameLayout.getLineLeft(1); + textWidth = Math.max(l1w, l2w); + float r = (AndroidUtilities.dp(11) + (int) Theme.chat_topicTextPaint.getTextSize()) / 1.5f; + boolean same = false; + AndroidUtilities.rectTmp.set(0, 0, R, R); + topicPath.arcTo(AndroidUtilities.rectTmp, 180, 90); + if (Math.abs(l1w - l2w) <= (padright - padright1)) { + l1w = Math.max(l1w, l2w + (padright - padright1)); + l2w = Math.max(l2w, l1w - (padright - padright1)); + same = true; + } + AndroidUtilities.rectTmp.set(padleft + padright1 + l1w - r, 0, padleft + padright1 + l1w, r); + topicPath.arcTo(AndroidUtilities.rectTmp, 270, 90); + float midly = AndroidUtilities.dp(11) + Theme.chat_topicTextPaint.getTextSize(); + float r2 = Math.min(r, Math.abs(l1w - AndroidUtilities.dp(18 - 5) - l2w)); + if (!same) { + if (l1w - (padright - padright1) > l2w) { + AndroidUtilities.rectTmp.set(padleft + padright1 + l1w - r2, midly - r2, padleft + padright1 + l1w, midly); + topicPath.arcTo(AndroidUtilities.rectTmp, 0, 90); + AndroidUtilities.rectTmp.set(padleft + padright + l2w, midly, padleft + padright + l2w + r2, midly + r2); + topicPath.arcTo(AndroidUtilities.rectTmp, 270, -90); + } else { + midly = topicHeight - midly; + AndroidUtilities.rectTmp.set(padleft + padright1 + l1w, midly - r2, padleft + padright1 + l1w + r2, midly); + topicPath.arcTo(AndroidUtilities.rectTmp, 180, -90); + AndroidUtilities.rectTmp.set(padleft + padright + l2w - r2, midly, padleft + padright + l2w, midly + r2); + topicPath.arcTo(AndroidUtilities.rectTmp, 270, 90); + } + } + topicArrowDrawable.setBounds( + (int) (padleft + padright + AndroidUtilities.dp(-4) + l2w - arrowsz), + (int) ((topicHeight - AndroidUtilities.dp(11) - Theme.chat_topicTextPaint.getTextSize() + topicHeight) / 2f - arrowsz / 2), + (int) (padleft + padright + AndroidUtilities.dp(-4) + l2w), + (int) ((topicHeight - AndroidUtilities.dp(11) - Theme.chat_topicTextPaint.getTextSize() + topicHeight) / 2f + arrowsz / 2) + ); + AndroidUtilities.rectTmp.set(padleft + padright + l2w - r, topicHeight - r, padleft + padright + l2w, topicHeight); + topicPath.arcTo(AndroidUtilities.rectTmp, 0, 90); + AndroidUtilities.rectTmp.set(0, topicHeight - R, R, topicHeight); + topicPath.arcTo(AndroidUtilities.rectTmp, 90, 90); + topicPath.close(); + } else if (lineCount == 1) { + topicHeight = AndroidUtilities.dp(11) + (int) Theme.chat_topicTextPaint.getTextSize(); + textWidth = topicNameLayout.getLineWidth(0) - topicNameLayout.getLineLeft(0); + AndroidUtilities.rectTmp.set(0, 0, padleft + padright + textWidth, topicHeight); + topicArrowDrawable.setBounds( + (int) (padleft + padright + AndroidUtilities.dp(-4) + textWidth - arrowsz), + (int) (topicHeight / 2f - arrowsz / 2), + (int) (padleft + padright + AndroidUtilities.dp(-4) + textWidth), + (int) (topicHeight / 2f + arrowsz / 2) + ); + topicPath.addRoundRect(AndroidUtilities.rectTmp, R, R, Path.Direction.CW); + } + topicWidth = (int) (padleft + padright -AndroidUtilities.dp(1) + textWidth); + int occupingHeight = 0; + if (!messageObject.isAnyKindOfSticker() && messageObject.type != MessageObject.TYPE_ROUND_VIDEO) { + occupingHeight += AndroidUtilities.dp(6) + topicHeight; + if (messageObject.type != MessageObject.TYPE_TEXT) { + occupingHeight += AndroidUtilities.dp(9); + } + } + + if (topicSelectorDrawable == null) { + topicSelectorDrawable = Theme.createSelectorDrawable(topicBackgroundColor, Theme.RIPPLE_MASK_ALL); + topicSelectorDrawable.setCallback(cell); + } else { + Theme.setSelectorDrawableColor(topicSelectorDrawable, topicBackgroundColor, true); + } + + topicPaint.setColor(topicBackgroundColor); + + if (topicIconDrawable != null) { + if (topicIconDrawableBounds == null) { + topicIconDrawableBounds = new Rect(); + } + topicIconDrawableBounds.set( + AndroidUtilities.dp(3 + 2f), + AndroidUtilities.dp(2 + (lineCount == 2 ? 3 : 0)), + AndroidUtilities.dp(3 + 2) + iconsz, + AndroidUtilities.dp(2 + (lineCount == 2 ? 3 : 0)) + iconsz + ); + topicIconDrawable.setBounds(topicIconDrawableBounds); + } + + return occupingHeight; + } + + public void onAttached(ChatMessageCell cell) { + if (topicIconDrawable instanceof AnimatedEmojiDrawable && cell != null) { + ((AnimatedEmojiDrawable) topicIconDrawable).addView(cell::invalidateOutbounds); + } + } + + public void onDetached(ChatMessageCell cell) { + if (topicIconDrawable instanceof AnimatedEmojiDrawable && cell != null) { + ((AnimatedEmojiDrawable) topicIconDrawable).removeView(cell::invalidateOutbounds); + } + } + + private void setupColors(int iconColor) { + if (lastMessageObject != null && lastMessageObject.shouldDrawWithoutBackground()) { + topicNameColor = getThemedColor(Theme.key_chat_stickerReplyNameText); + } else if (lastMessageObject != null && lastMessageObject.isOutOwner()) { + topicNameColor = getThemedColor(Theme.key_chat_outReactionButtonText); + topicBackgroundColor = ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_outReactionButtonBackground), 38); + } else { + if (topicHSV == null) { + topicHSV = new float[3]; + } + Color.colorToHSV(iconColor, topicHSV); + float hue = topicHSV[0]; + float sat = topicHSV[1]; + if (sat <= 0.02f) { + topicNameColor = getThemedColor(Theme.key_chat_inReactionButtonText); + topicBackgroundColor = ColorUtils.setAlphaComponent(getThemedColor(Theme.key_chat_inReactionButtonBackground), 38); + } else { + Color.colorToHSV(getThemedColor(Theme.key_chat_inReactionButtonText), topicHSV); + topicHSV[0] = hue; + float[] hueRanges = Theme.isCurrentThemeDark() ? darkHueRanges : lightHueRanges; + float[] satValues = Theme.isCurrentThemeDark() ? darkSatValues : lightSatValues; + float[] valValues = Theme.isCurrentThemeDark() ? darkValValues : lightValValues; + for (int i = 1; i < hueRanges.length; ++i) { + if (hue <= hueRanges[i]) { + float t = (hue - hueRanges[i - 1]) / (hueRanges[i] - hueRanges[i - 1]); + topicHSV[1] = AndroidUtilities.lerp(satValues[i - 1], satValues[i], t); + topicHSV[2] = AndroidUtilities.lerp(valValues[i - 1], valValues[i], t); + break; + } + } + topicNameColor = Color.HSVToColor(Color.alpha(getThemedColor(Theme.key_chat_inReactionButtonText)), topicHSV); + topicBackgroundColor = Color.HSVToColor(38, topicHSV); + } + } + } + + public boolean checkTouchEvent(MotionEvent event) { + if (topicHitRect == null) { + topicPressed = false; + return false; + } + boolean hit = topicHitRect.contains(event.getX(), event.getY()); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (hit) { + if (topicSelectorDrawable != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + topicSelectorDrawable.setHotspot(event.getX() - topicHitRect.left, event.getY() - topicHitRect.top); + } + topicSelectorDrawable.setState(pressedState); + } + topicPressed = true; + } else { + topicPressed = false; + } + return topicPressed; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (topicPressed != hit) { + if (topicPressed && topicSelectorDrawable != null) { + topicSelectorDrawable.setState(idleState); + } + topicPressed = hit; + } + return topicPressed; + } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + if (topicPressed) { + topicPressed = false; + if (topicSelectorDrawable != null) { + topicSelectorDrawable.setState(idleState); + } + if (event.getAction() == MotionEvent.ACTION_UP) { + onClick(); + return true; + } + } + } + return false; + } + + public int width() { + return topicWidth; + } + + public int height() { + return topicHeight; + } + + public void draw(Canvas canvas, float x, float y, float alpha) { + if (topicIconWaiting && topicIconDrawable instanceof AnimatedEmojiDrawable) { + int iconColor = AnimatedEmojiDrawable.getDominantColor((AnimatedEmojiDrawable) topicIconDrawable); + if (iconColor != 0) { + topicIconWaiting = false; + setupColors(iconColor); + } + } + canvas.save(); + if (lastMessageObject != null && lastMessageObject.shouldDrawWithoutBackground()) { + topicPath.offset(x, y); + + int oldAlpha1 = -1, oldAlpha2 = -1; + if (alpha < 1) { + oldAlpha1 = getThemedPaint(Theme.key_paint_chatActionBackground).getAlpha(); + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha((int) (oldAlpha1 * alpha)); + } + canvas.drawPath(topicPath, getThemedPaint(Theme.key_paint_chatActionBackground)); + if (hasGradientService()) { + if (alpha < 1) { + oldAlpha2 = Theme.chat_actionBackgroundGradientDarkenPaint.getAlpha(); + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha((int) (oldAlpha2 * alpha)); + } + canvas.drawPath(topicPath, Theme.chat_actionBackgroundGradientDarkenPaint); + } + if (oldAlpha1 >= 0) { + getThemedPaint(Theme.key_paint_chatActionBackground).setAlpha(oldAlpha1); + } + if (oldAlpha2 >= 0) { + Theme.chat_actionBackgroundGradientDarkenPaint.setAlpha(oldAlpha2); + } + topicPath.offset(-x, -y); + canvas.translate(x, y); + } else { + canvas.translate(x, y); + if (topicPath != null && topicPaint != null) { + if (topicBackgroundColorAnimated != null) { + topicPaint.setColor(topicBackgroundColorAnimated.set(topicBackgroundColor)); + } else { + topicPaint.setColor(topicBackgroundColor); + } + int wasAlpha = topicPaint.getAlpha(); + topicPaint.setAlpha((int) (wasAlpha * alpha)); + canvas.drawPath(topicPath, topicPaint); + topicPaint.setAlpha(wasAlpha); + } + } + if (topicHitRect == null) { + topicHitRect = new RectF(); + } + topicHitRect.set(x, y, x + topicWidth, y + topicHeight); + if (topicSelectorDrawable != null) { + canvas.save(); + canvas.clipPath(topicPath); + AndroidUtilities.rectTmp2.set(0, 0, topicWidth, topicHeight); + topicSelectorDrawable.setBounds(AndroidUtilities.rectTmp2); + topicSelectorDrawable.draw(canvas); + canvas.restore(); + } + int nameColor = topicNameColor; + if (topicNameLayout != null) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(17) + Theme.chat_topicTextPaint.getTextSize(), AndroidUtilities.dp(4.5f)); + if (topicNameColorAnimated != null) { + Theme.chat_topicTextPaint.setColor(nameColor = topicNameColorAnimated.set(topicNameColor)); + } else { + Theme.chat_topicTextPaint.setColor(nameColor = topicNameColor); + } + Theme.chat_topicTextPaint.setAlpha((int) (Theme.chat_topicTextPaint.getAlpha() * alpha)); + topicNameLayout.draw(canvas); + canvas.restore(); + } + if (topicArrowDrawable != null) { + int arrowColor = ColorUtils.setAlphaComponent(nameColor, 140); + if (topicArrowColor != arrowColor) { + topicArrowDrawable.setColorFilter(new PorterDuffColorFilter(topicArrowColor = arrowColor, PorterDuff.Mode.MULTIPLY)); + } + topicArrowDrawable.draw(canvas); + } + canvas.restore(); + } + + public void drawOutbounds(Canvas canvas, float alpha) { + if (topicHitRect != null) { + canvas.save(); + canvas.translate(topicHitRect.left, topicHitRect.top); + topicIconDrawable.setAlpha((int) (255 * alpha)); + topicIconDrawable.setBounds(topicIconDrawableBounds); + topicIconDrawable.draw(canvas); + canvas.restore(); + } + } + + public void resetClick() { + if (topicSelectorDrawable != null) { + topicSelectorDrawable.setState(idleState); + } + } + + private int getThemedColor(String key) { + Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; + return color != null ? color : Theme.getColor(key); + } + + private Paint getThemedPaint(String key) { + Paint paint = resourcesProvider != null ? resourcesProvider.getPaint(key) : null; + return paint != null ? paint : Theme.getThemePaint(key); + } + + private boolean hasGradientService() { + return resourcesProvider != null ? resourcesProvider.hasGradientService() : Theme.hasGradientService(); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index 06ffb6325..0c795fa19 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -68,6 +68,7 @@ import org.telegram.messenger.UserObject; import org.telegram.messenger.voip.VoIPService; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.AlertDialog; @@ -486,6 +487,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent } avatars = new AvatarsImageView(context, false); + avatars.setAvatarsTextSize(AndroidUtilities.dp(21)); avatars.setDelegate(() -> updateAvatars(true)); avatars.setVisibility(GONE); addView(avatars, LayoutHelper.createFrame(108, 36, Gravity.LEFT | Gravity.TOP)); @@ -1973,7 +1975,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent frameLayout.invalidate(); } - updateAvatars(avatars.avatarsDarawable.wasDraw && updateAnimated); + updateAvatars(avatars.avatarsDrawable.wasDraw && updateAnimated); } else { if (voIPService != null && voIPService.groupCall != null) { updateAvatars(currentStyle == STYLE_ACTIVE_GROUP_CALL); @@ -2044,14 +2046,14 @@ public class FragmentContextView extends FrameLayout implements NotificationCent private void updateAvatars(boolean animated) { if (!animated) { - if (avatars.avatarsDarawable.transitionProgressAnimator != null) { - avatars.avatarsDarawable.transitionProgressAnimator.cancel(); - avatars.avatarsDarawable.transitionProgressAnimator = null; + if (avatars.avatarsDrawable.transitionProgressAnimator != null) { + avatars.avatarsDrawable.transitionProgressAnimator.cancel(); + avatars.avatarsDrawable.transitionProgressAnimator = null; } } ChatObject.Call call; TLRPC.User userCall; - if (avatars.avatarsDarawable.transitionProgressAnimator == null) { + if (avatars.avatarsDrawable.transitionProgressAnimator == null) { int currentAccount; if (currentStyle == STYLE_INACTIVE_GROUP_CALL) { if (chatActivity != null) { @@ -2265,41 +2267,4 @@ public class FragmentContextView extends FrameLayout implements NotificationCent Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null; return color != null ? color : Theme.getColor(key); } - - public interface ChatActivityInterface { - - default ChatObject.Call getGroupCall() { - return null; - } - - default TLRPC.Chat getCurrentChat() { - return null; - } - - default TLRPC.User getCurrentUser() { - return null; - } - - long getDialogId(); - - default void scrollToMessageId(int id, int i, boolean b, int i1, boolean b1, int i2) { - - } - - default boolean shouldShowImport() { - return false; - } - - default boolean openedWithLivestream() { - return false; - } - - default long getMergeDialogId() { - return 0; - } - - default int getTopicId() { - return 0; - } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java index 0296d6303..c52603c5b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPip.java @@ -674,7 +674,7 @@ public class GroupCallPip implements NotificationCenter.NotificationCenterDelega } private void updateAvatars(boolean animated) { - if (avatarsImageView.avatarsDarawable.transitionProgressAnimator == null) { + if (avatarsImageView.avatarsDrawable.transitionProgressAnimator == null) { ChatObject.Call call; VoIPService voIPService = VoIPService.getSharedInstance(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java index 734edc8da..018d6a144 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/GroupCallPipAlertView.java @@ -280,9 +280,11 @@ public class GroupCallPipAlertView extends LinearLayout implements VoIPService.S super.onAttachedToWindow(); VoIPService service = VoIPService.getSharedInstance(); if (service != null && service.groupCall != null) { - int color2 = AvatarDrawable.getColorForId(service.getChat().id); AvatarDrawable avatarDrawable = new AvatarDrawable(); - avatarDrawable.setColor(color2); + avatarDrawable.setColor( + Theme.getColor(Theme.keys_avatar_background[AvatarDrawable.getColorIndex(service.getChat().id)]), + Theme.getColor(Theme.keys_avatar_background2[AvatarDrawable.getColorIndex(service.getChat().id)]) + ); avatarDrawable.setInfo(service.getChat()); avatarImageView.setImage(ImageLocation.getForLocal(service.getChat().photo.photo_small), "50_50", avatarDrawable, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java index b310b25f7..93187b031 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java @@ -205,6 +205,9 @@ public class HintView extends FrameLayout { if (!messageObject.isOutOwner() && cell.isDrawNameLayout()) { top += AndroidUtilities.dp(20); } + if (!messageObject.shouldDrawWithoutBackground() && cell.isDrawTopic()) { + top += AndroidUtilities.dp(5) + cell.getDrawTopicHeight(); + } } if (!isTopArrow && top <= getMeasuredHeight() + AndroidUtilities.dp(10)) { return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java index 09eda6319..3462bd45f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java @@ -30,6 +30,7 @@ public class LetterDrawable extends Drawable { public static Paint paint = new Paint(); private static TextPaint namePaint; private static TextPaint namePaintTopic; + private static TextPaint namePaintSmallTopic; private RectF rect = new RectF(); private StaticLayout textLayout; @@ -40,6 +41,7 @@ public class LetterDrawable extends Drawable { public static final int STYLE_DEFAULT = 0; public static final int STYLE_TOPIC_DRAWABLE = 1; + public static final int STYLE_SMALL_TOPIC_DRAWABLE = 2; int style; final TextPaint textPaint; public float scale = 1f; @@ -48,7 +50,6 @@ public class LetterDrawable extends Drawable { this(null, 0); } - public LetterDrawable(Theme.ResourcesProvider resourcesProvider, int style) { super(); this.style = style; @@ -60,7 +61,7 @@ public class LetterDrawable extends Drawable { paint.setColor(Theme.getColor(Theme.key_sharedMedia_linkPlaceholder, resourcesProvider)); namePaint.setColor(Theme.getColor(Theme.key_sharedMedia_linkPlaceholderText, resourcesProvider)); textPaint = namePaint; - } else { + } else if (style == STYLE_TOPIC_DRAWABLE) { if (namePaintTopic == null) { namePaintTopic = new TextPaint(Paint.ANTI_ALIAS_FLAG); } @@ -68,6 +69,14 @@ public class LetterDrawable extends Drawable { namePaintTopic.setTextSize(AndroidUtilities.dp(13)); namePaintTopic.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); textPaint = namePaintTopic; + } else { + if (namePaintSmallTopic == null) { + namePaintSmallTopic = new TextPaint(Paint.ANTI_ALIAS_FLAG); + } + namePaintSmallTopic.setColor(Color.WHITE); + namePaintSmallTopic.setTextSize(Theme.chat_topicTextPaint.getTextSize() * .75f); + namePaintSmallTopic.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD)); + textPaint = namePaintSmallTopic; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java new file mode 100644 index 000000000..47ac696ea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ListView/AdapterWithDiffUtils.java @@ -0,0 +1,73 @@ +package org.telegram.ui.Components.ListView; + +import androidx.recyclerview.widget.DiffUtil; + +import org.telegram.ui.Components.RecyclerListView; + +import java.util.ArrayList; + +public abstract class AdapterWithDiffUtils extends RecyclerListView.SelectionAdapter { + + DiffUtilsCallback callback = new DiffUtilsCallback(); + + public void setItems(ArrayList oldItems, ArrayList newItems) { + if (newItems == null) { + newItems = new ArrayList<>(); + } + callback.setItems(oldItems, newItems); + DiffUtil.calculateDiff(callback).dispatchUpdatesTo(this); + } + + + public static class Item { + public final int viewType; + public boolean selectable; + + public Item(int viewType, boolean selectable) { + this.viewType = viewType; + this.selectable = selectable; + } + + boolean compare(Item item) { + if (viewType != item.viewType) { + return false; + } + if (this.equals(item)) { + return true; + } + return false; + } + + } + + private class DiffUtilsCallback extends DiffUtil.Callback { + + ArrayList oldItems; + ArrayList newItems; + + public void setItems(ArrayList oldItems, ArrayList newItems) { + this.oldItems = oldItems; + this.newItems = newItems; + } + + @Override + public int getOldListSize() { + return oldItems.size(); + } + + @Override + public int getNewListSize() { + return newItems.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return oldItems.get(oldItemPosition).compare(newItems.get(newItemPosition)); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java index ecb6f2e86..e4eb205db 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LoadingDrawable.java @@ -29,6 +29,8 @@ public class LoadingDrawable extends Drawable { private long start = -1; private LinearGradient gradient; private int gradientColor1, gradientColor2; + public String colorKey1 = Theme.key_dialogBackground; + public String colorKey2 = Theme.key_dialogBackgroundGray; private int gradientWidth; public Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -46,8 +48,8 @@ public class LoadingDrawable extends Drawable { return; } int gwidth = Math.min(AndroidUtilities.dp(400), bounds.width()); - int color1 = Theme.getColor(Theme.key_dialogBackground, resourcesProvider); - int color2 = Theme.getColor(Theme.key_dialogBackgroundGray, resourcesProvider); + int color1 = Theme.getColor(colorKey1, resourcesProvider); + int color2 = Theme.getColor(colorKey2, resourcesProvider); if (gradient == null || gwidth != gradientWidth || color1 != gradientColor1 || color2 != gradientColor2) { gradientWidth = gwidth; gradientColor1 = color1; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java index 3c545e696..2f01858be 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MessageContainsEmojiButton.java @@ -149,6 +149,8 @@ public class MessageContainsEmojiButton extends FrameLayout implements Notificat mainText = parts[0]; endText = parts[1]; loadingDrawable = new LoadingDrawable(resourcesProvider); + loadingDrawable.colorKey1 = Theme.key_actionBarDefaultSubmenuBackground; + loadingDrawable.colorKey2 = Theme.key_listSelector; loadingDrawable.paint.setPathEffect(new CornerPathEffect(AndroidUtilities.dp(4))); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java index 54d817c5b..f522e9fc7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/LimitReachedBottomSheet.java @@ -120,6 +120,7 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { } else if (type == TYPE_TO_MANY_COMMUNITIES) { loadInactiveChannels(); } + updatePremiumButtonText(); } @Override @@ -128,7 +129,6 @@ public class LimitReachedBottomSheet extends BottomSheetWithRecyclerListView { Context context = containerView.getContext(); premiumButtonView = new PremiumButtonView(context, true); - updatePremiumButtonText(); if (!hasFixedSize) { divider = new View(context) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java index 25e996c90..bfc5c17ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumFeatureBottomSheet.java @@ -65,6 +65,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati SvgHelper.SvgDrawable svgIcon; private final int startType; private final boolean onlySelectedType; + private boolean forceAbout; private PremiumPreviewFragment.SubscriptionTier selectedTier; private int gradientAlpha = 255; @@ -316,7 +317,7 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati if (fragment != null && fragment.getVisibleDialog() != null) { fragment.getVisibleDialog().dismiss(); } - if (onlySelectedType && fragment != null) { + if ((onlySelectedType || forceAbout) && fragment != null) { fragment.presentFragment(new PremiumPreviewFragment(PremiumPreviewFragment.featureTypeToServerString(featureData.type))); } else { PremiumPreviewFragment.buyPremium(fragment, selectedTier, PremiumPreviewFragment.featureTypeToServerString(featureData.type)); @@ -414,9 +415,17 @@ public class PremiumFeatureBottomSheet extends BottomSheet implements Notificati containerView.setPadding(backgroundPaddingLeft, backgroundPaddingTop - 1, backgroundPaddingLeft, 0); } + public PremiumFeatureBottomSheet setForceAbout() { + this.forceAbout = true; + premiumButtonView.clearOverlayText(); + setButtonText(); + return this; + } private void setButtonText() { - if (onlySelectedType) { + if (forceAbout) { + premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.AboutTelegramPremium)); + } else if (onlySelectedType) { if (startType == PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS) { premiumButtonView.buttonTextView.setText(LocaleController.getString(R.string.UnlockPremiumReactions)); premiumButtonView.setIcon(R.raw.unlock_icon); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumLockIconView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumLockIconView.java index 31c377838..f132347f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumLockIconView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/PremiumLockIconView.java @@ -172,7 +172,7 @@ public class PremiumLockIconView extends ImageView { int x = (int) (stepW * i); int y = (int) (stepH * j); int pixel = bitmap.getPixel(x, y); - if (pixel != Color.TRANSPARENT) { + if (Color.alpha(pixel) > 200) { r += Color.red(pixel); g += Color.green(pixel); b += Color.blue(pixel); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java index 21ba44e82..b550ba52c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Premium/VideoScreenPreview.java @@ -244,8 +244,8 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, } } attachFileName = FileLoader.getAttachFileName(document); - imageReceiver.setImage(null, null, drawable, null, null, 1); - FileLoader.getInstance(currentAccount).loadFile(document, null, FileLoader.PRIORITY_HIGH, 0); + imageReceiver.setImage(null, null, drawable, null, premiumPromo, 1); + FileLoader.getInstance(currentAccount).loadFile(document, premiumPromo, FileLoader.PRIORITY_HIGH, 0); this.document = document; Utilities.globalQueue.postRunnable(() -> { File file = FileLoader.getInstance(currentAccount).getPathToAttach(document); @@ -577,7 +577,7 @@ public class VideoScreenPreview extends FrameLayout implements PagerHeaderView, "&dc=" + document.dc_id + "&size=" + document.size + "&mime=" + URLEncoder.encode(document.mime_type, "UTF-8") + - "&rid=" + FileLoader.getInstance(currentAccount).getFileReference(document) + + "&rid=" + FileLoader.getInstance(currentAccount).getFileReference(MediaDataController.getInstance(currentAccount).getPremiumPromo()) + "&name=" + URLEncoder.encode(FileLoader.getDocumentFileName(document), "UTF-8") + "&reference=" + Utilities.bytesToHex(document.file_reference != null ? document.file_reference : new byte[0]); uri = Uri.parse("tg://" + attachFileName + params); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java index 72b695a1a..6e254f98e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PullForegroundDrawable.java @@ -7,10 +7,12 @@ import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.Drawable; import android.text.TextPaint; import android.view.View; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index c6085094e..45b19d93b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -108,8 +108,8 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private boolean applyTransformation; private boolean needScale; private final RectF dstRect = new RectF(); - private RectF dstRectBackground; - private Paint backgroundPaint; + private RectF[] dstRectBackground = new RectF[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; + private Paint[] backgroundPaint = new Paint[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; protected static final Handler uiHandler = new Handler(Looper.getMainLooper()); protected volatile boolean isRunning; protected volatile boolean isRecycled; @@ -175,6 +175,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (lottieCacheGenerateQueue == null) { createCacheGenQueue(); } + BitmapsCache.incrementTaskCounter(); lottieCacheGenerateQueue.postRunnable(cacheGenerateTask = () -> { BitmapsCache bitmapsCacheFinal = bitmapsCache; if (bitmapsCacheFinal != null) { @@ -189,7 +190,10 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma private Runnable uiRunnableCacheFinished = new Runnable() { @Override public void run() { - cacheGenerateTask = null; + if (cacheGenerateTask != null) { + BitmapsCache.decrementTaskCounter(); + cacheGenerateTask = null; + } generatingCache = false; decodeFrameFinishedInternal(); } @@ -205,6 +209,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma protected void checkRunningTasks() { if (cacheGenerateTask != null) { lottieCacheGenerateQueue.cancelRunnable(cacheGenerateTask); + BitmapsCache.decrementTaskCounter(); cacheGenerateTask = null; } if (!hasParentView() && nextRenderingBitmap != null && loadFrameTask != null) { @@ -740,6 +745,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (bitmapsCache != null) { bitmapsCache.cancelCreate(); } + BitmapsCache.decrementTaskCounter(); }, 600); } else if (!mustCancel && cancelCache != null) { AndroidUtilities.cancelRunOnUIThread(cancelCache); @@ -905,10 +911,6 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma } protected boolean scheduleNextGetFrame() { - return scheduleNextGetFrame(false); - } - - protected boolean scheduleNextGetFrame(boolean allowGroupedUpdateLocal) { if (loadFrameTask != null || nextRenderingBitmap != null || !canLoadFrames() || loadingInBackground || destroyWhenDone || !isRunning && (!decodeSingleFrame || decodeSingleFrame && singleFrameDecoded)) { return false; } @@ -924,8 +926,8 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma newReplaceColors = null; } loadFrameTask = loadFrameRunnable; - if (allowGroupedUpdateLocal && shouldLimitFps) { - DispatchQueuePoolBackground.execute(loadFrameTask); + if (shouldLimitFps) { + DispatchQueuePoolBackground.execute(loadFrameTask, frameWaitSync != null); } else { loadFrameRunnableQueue.execute(loadFrameTask); } @@ -976,7 +978,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (resetFrame && !isRunning) { isRunning = true; } - if (scheduleNextGetFrame(false)) { + if (scheduleNextGetFrame()) { if (!async) { try { frameWaitSync.await(); @@ -1080,27 +1082,27 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma } } } - scheduleNextGetFrame(true); + scheduleNextGetFrame(); } @Override public void draw(Canvas canvas) { - drawInternal(canvas, false, 0); + drawInternal(canvas, false, 0, 0); } - public void drawInBackground(Canvas canvas, float x, float y, float w, float h, int alpha, ColorFilter colorFilter) { - if (dstRectBackground == null) { - dstRectBackground = new RectF(); - backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - backgroundPaint.setFilterBitmap(true); + public void drawInBackground(Canvas canvas, float x, float y, float w, float h, int alpha, ColorFilter colorFilter, int threadIndex) { + if (dstRectBackground[threadIndex] == null) { + dstRectBackground[threadIndex] = new RectF(); + backgroundPaint[threadIndex] = new Paint(Paint.ANTI_ALIAS_FLAG); + backgroundPaint[threadIndex].setFilterBitmap(true); } - backgroundPaint.setAlpha(alpha); - backgroundPaint.setColorFilter(colorFilter); - dstRectBackground.set(x, y, x + w, y + h); - drawInternal(canvas, true, 0); + backgroundPaint[threadIndex].setAlpha(alpha); + backgroundPaint[threadIndex].setColorFilter(colorFilter); + dstRectBackground[threadIndex].set(x, y, x + w, y + h); + drawInternal(canvas, true, 0, threadIndex); } - public void drawInternal(Canvas canvas, boolean drawInBackground, long time) { + public void drawInternal(Canvas canvas, boolean drawInBackground, long time, int threadIndex) { if (!canLoadFrames() || destroyWhenDone) { return; } @@ -1108,8 +1110,8 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma updateCurrentFrame(time, false); } - RectF rect = drawInBackground ? dstRectBackground : dstRect; - Paint paint = drawInBackground ? backgroundPaint : getPaint(); + RectF rect = drawInBackground ? dstRectBackground[threadIndex] : dstRect; + Paint paint = drawInBackground ? backgroundPaint[threadIndex] : getPaint(); if (paint.getAlpha() == 0) { return; @@ -1163,7 +1165,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma } if (isRunning) { if (renderingBitmap == null && nextRenderingBitmap == null) { - scheduleNextGetFrame(true); + scheduleNextGetFrame(); } else if (nextRenderingBitmap != null && (renderingBitmap == null || (timeDiff >= timeCheck && !skipFrameUpdate))) { if (vibrationPattern != null && currentParentView != null && allowVibration) { Integer force = vibrationPattern.get(currentFrame - 1); @@ -1322,13 +1324,22 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma if (lottieCacheGenerateQueue == null) { createCacheGenQueue(); } - lottieCacheGenerateQueue.postRunnable(cacheGenerateTask = () -> { - BitmapsCache bitmapsCacheFinal = bitmapsCache; - if (bitmapsCacheFinal != null) { - bitmapsCacheFinal.createCache(); - } - AndroidUtilities.runOnUIThread(onReady); - }); + if (cacheGenerateTask == null) { + BitmapsCache.incrementTaskCounter(); + lottieCacheGenerateQueue.postRunnable(cacheGenerateTask = () -> { + BitmapsCache bitmapsCacheFinal = bitmapsCache; + if (bitmapsCacheFinal != null) { + bitmapsCacheFinal.createCache(); + } + AndroidUtilities.runOnUIThread(() -> { + onReady.run(); + if (cacheGenerateTask != null) { + cacheGenerateTask = null; + BitmapsCache.decrementTaskCounter(); + } + }); + }); + } }); } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java index f72f01335..740c65edd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedHeaderView.java @@ -70,7 +70,7 @@ public class ReactedHeaderView extends FrameLayout { addView(titleView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 40, 0, 62, 0)); avatarsImageView = new AvatarsImageView(context, false); - avatarsImageView.setStyle(AvatarsDarawable.STYLE_MESSAGE_SEEN); + avatarsImageView.setStyle(AvatarsDrawable.STYLE_MESSAGE_SEEN); addView(avatarsImageView, LayoutHelper.createFrameRelatively(24 + 12 + 12 + 8, LayoutHelper.MATCH_PARENT, Gravity.END | Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); iconView = new ImageView(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java index bfd825657..41b762e57 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactedUsersListView.java @@ -8,16 +8,13 @@ import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; -import android.text.TextUtils; import android.util.LongSparseArray; -import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import android.widget.LinearLayout; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; @@ -187,6 +184,7 @@ public class ReactedUsersListView extends FrameLayout { return !customReactionsEmoji.isEmpty() && messageContainsEmojiButton != null ? messageContainsEmojiButton.getMeasuredHeight() + AndroidUtilities.dp(8) : 0; } }; + loadingView.setColors(Theme.key_actionBarDefaultSubmenuBackground, Theme.key_listSelector, null); loadingView.setIsSingleCell(true); loadingView.setItemsCount(predictiveCount); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java index 5e0c28988..1963c3213 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsLayoutInBubble.java @@ -13,7 +13,6 @@ import android.view.ViewConfiguration; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.ChatListItemAnimator; -import org.checkerframework.checker.units.qual.A; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.DocumentObject; @@ -28,7 +27,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Components.AnimatedEmojiDrawable; -import org.telegram.ui.Components.AvatarsDarawable; +import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.CounterView; import java.util.ArrayList; @@ -218,12 +217,12 @@ public class ReactionsLayoutInBubble { button.height = AndroidUtilities.dp(14); } else { button.width = (int) (AndroidUtilities.dp(8) + AndroidUtilities.dp(20) + AndroidUtilities.dp(4)); - if (button.avatarsDarawable != null && button.users.size() > 0) { + if (button.avatarsDrawable != null && button.users.size() > 0) { button.users.size(); int c1 = 1; int c2 = button.users.size() > 1 ? button.users.size() - 1 : 0; button.width += AndroidUtilities.dp(2) + c1 * AndroidUtilities.dp(20) + c2 * AndroidUtilities.dp(20) * 0.8f + AndroidUtilities.dp(1); - button.avatarsDarawable.height = AndroidUtilities.dp(26); + button.avatarsDrawable.height = AndroidUtilities.dp(26); } else { button.width += button.counterDrawable.textPaint.measureText(button.countText) + AndroidUtilities.dp(8); } @@ -350,7 +349,7 @@ public class ReactionsLayoutInBubble { } if (lastButton != null) { lastDrawingReactionButtonsTmp.remove(button.key); - if (button.x != lastButton.x || button.y != lastButton.y || button.width != lastButton.width || button.count != lastButton.count || button.choosen != lastButton.choosen || button.avatarsDarawable != null || lastButton.avatarsDarawable != null) { + if (button.x != lastButton.x || button.y != lastButton.y || button.width != lastButton.width || button.count != lastButton.count || button.choosen != lastButton.choosen || button.avatarsDrawable != null || lastButton.avatarsDrawable != null) { button.animateFromX = lastButton.x; button.animateFromY = lastButton.y; button.animateFromWidth = lastButton.width; @@ -363,15 +362,15 @@ public class ReactionsLayoutInBubble { button.counterDrawable.setCount(lastButton.count, false); button.counterDrawable.setCount(button.count, true); } - if (button.avatarsDarawable != null || lastButton.avatarsDarawable != null) { - if (button.avatarsDarawable == null) { + if (button.avatarsDrawable != null || lastButton.avatarsDrawable != null) { + if (button.avatarsDrawable == null) { button.setUsers(new ArrayList<>()); } - if (lastButton.avatarsDarawable == null) { + if (lastButton.avatarsDrawable == null) { lastButton.setUsers(new ArrayList<>()); } if (!equalsUsersList(lastButton.users, button.users)) { - button.avatarsDarawable.animateFromState(lastButton.avatarsDarawable, currentAccount, false); + button.avatarsDrawable.animateFromState(lastButton.avatarsDrawable, currentAccount, false); } } changed = true; @@ -493,7 +492,7 @@ public class ReactionsLayoutInBubble { int lastDrawnTextColor; int lastDrawnBackgroundColor; boolean isSelected; - AvatarsDarawable avatarsDarawable; + AvatarsDrawable avatarsDrawable; ArrayList users; public ReactionButton(TLRPC.ReactionCount reactionCount, boolean isSmall) { @@ -627,12 +626,12 @@ public class ReactionsLayoutInBubble { canvas.restore(); } - if (avatarsDarawable != null) { + if (avatarsDrawable != null) { canvas.save(); canvas.translate(AndroidUtilities.dp(10) + AndroidUtilities.dp(20) + AndroidUtilities.dp(2), 0); - avatarsDarawable.setAlpha(alpha); - avatarsDarawable.setTransitionProgress(progress); - avatarsDarawable.onDraw(canvas); + avatarsDrawable.setAlpha(alpha); + avatarsDrawable.setTransitionProgress(progress); + avatarsDrawable.onDraw(canvas); canvas.restore(); } } @@ -688,25 +687,25 @@ public class ReactionsLayoutInBubble { this.users = users; if (users != null) { Collections.sort(users, usersComparator); - if (avatarsDarawable == null) { - avatarsDarawable = new AvatarsDarawable(parentView, false); - avatarsDarawable.transitionDuration = ChatListItemAnimator.DEFAULT_DURATION; - avatarsDarawable.transitionInterpolator = ChatListItemAnimator.DEFAULT_INTERPOLATOR; - avatarsDarawable.setSize(AndroidUtilities.dp(20)); - avatarsDarawable.width = AndroidUtilities.dp(100); - avatarsDarawable.height = height; - avatarsDarawable.setAvatarsTextSize(AndroidUtilities.dp(22)); + if (avatarsDrawable == null) { + avatarsDrawable = new AvatarsDrawable(parentView, false); + avatarsDrawable.transitionDuration = ChatListItemAnimator.DEFAULT_DURATION; + avatarsDrawable.transitionInterpolator = ChatListItemAnimator.DEFAULT_INTERPOLATOR; + avatarsDrawable.setSize(AndroidUtilities.dp(20)); + avatarsDrawable.width = AndroidUtilities.dp(100); + avatarsDrawable.height = height; + avatarsDrawable.setAvatarsTextSize(AndroidUtilities.dp(22)); if (attached) { - avatarsDarawable.onAttachedToWindow(); + avatarsDrawable.onAttachedToWindow(); } } for (int i = 0; i < users.size(); i++) { if (i == 3) { break; } - avatarsDarawable.setObject(i, currentAccount, users.get(i)); + avatarsDrawable.setObject(i, currentAccount, users.get(i)); } - avatarsDarawable.commitTransition(false); + avatarsDrawable.commitTransition(false); } } @@ -714,8 +713,8 @@ public class ReactionsLayoutInBubble { if (imageReceiver != null) { imageReceiver.onAttachedToWindow(); } - if (avatarsDarawable != null) { - avatarsDarawable.onAttachedToWindow(); + if (avatarsDrawable != null) { + avatarsDrawable.onAttachedToWindow(); } if (animatedEmojiDrawable != null) { animatedEmojiDrawable.addView(parentView); @@ -726,8 +725,8 @@ public class ReactionsLayoutInBubble { if (imageReceiver != null) { imageReceiver.onDetachedFromWindow(); } - if (avatarsDarawable != null) { - avatarsDarawable.onDetachedFromWindow(); + if (avatarsDrawable != null) { + avatarsDrawable.onDetachedFromWindow(); } if (animatedEmojiDrawable != null) { animatedEmojiDrawable.removeView(parentView); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java index 89787a73f..832579cc2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Reactions/ReactionsUtils.java @@ -8,7 +8,7 @@ import org.telegram.ui.Components.AnimatedEmojiSpan; public class ReactionsUtils { - public static final String APPEAR_ANIMATION_FILTER = "30_30_nolimit_pcache"; + public static final String APPEAR_ANIMATION_FILTER = "30_30_nolimit"; public static final String SELECT_ANIMATION_FILTER = "60_60_pcache"; public static final String ACTIVATE_ANIMATION_FILTER = "30_30_pcache"; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java index 6675f4ae4..852481f5b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ReactionsContainerLayout.java @@ -56,6 +56,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.AlertDialog; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumLockIconView; import org.telegram.ui.Components.Reactions.CustomEmojiReactionsWindow; @@ -272,13 +273,12 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio }); recyclerListView.setLayoutManager(linearLayoutManager); recyclerListView.setOverScrollMode(View.OVER_SCROLL_NEVER); - recyclerListView.setAdapter(listAdapter = new RecyclerView.Adapter() { + recyclerListView.setAdapter(listAdapter = new AdapterWithDiffUtils() { - int rowCount; - int reactionsStartRow; - int reactionsEndRow; - int premiumUnlockButtonRow; - int customReactionsEmojiRow; + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + return false; + } @NonNull @Override @@ -286,10 +286,10 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio View view; switch (viewType) { default: - case 0: + case VIEW_TYPE_REACTION: view = new ReactionHolderView(context, true); break; - case 1: + case VIEW_TYPE_PREMIUM_BUTTON: premiumLockContainer = new FrameLayout(context); premiumLockIconView = new PremiumLockIconView(context, PremiumLockIconView.TYPE_REACTIONS); premiumLockIconView.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_actionBarDefaultSubmenuItemIcon), Theme.getColor(Theme.key_dialogBackground), 0.7f)); @@ -305,7 +305,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio }); view = premiumLockContainer; break; - case 2: + case VIEW_TYPE_CUSTOM_EMOJI_BUTTON: customReactionsContainer = new CustomReactionsContainer(context); customEmojiReactionsIconView = new InternalImageView(context); customEmojiReactionsIconView.setImageResource(R.drawable.msg_reactions_expand); @@ -328,45 +328,67 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if (holder.getItemViewType() == 0) { + if (holder.getItemViewType() == VIEW_TYPE_REACTION) { ReactionHolderView h = (ReactionHolderView) holder.itemView; h.setScaleX(1); h.setScaleY(1); - h.setReaction(visibleReactionsList.get(position), position); + h.setReaction(items.get(position).reaction, position); } } @Override public int getItemCount() { - return rowCount; + return items.size(); } @Override public int getItemViewType(int position) { - if (position >= 0 && position < visibleReactionsList.size()) { - return 0; - } - if (position == premiumUnlockButtonRow) { - return 1; - } - return 2; + return items.get(position).viewType; } + ArrayList items = new ArrayList<>(); + ArrayList oldItems = new ArrayList<>(); + + private static final int VIEW_TYPE_REACTION = 0; + private static final int VIEW_TYPE_PREMIUM_BUTTON = 1; + private static final int VIEW_TYPE_CUSTOM_EMOJI_BUTTON = 2; @Override public void notifyDataSetChanged() { - rowCount = 0; - premiumUnlockButtonRow = -1; - customReactionsEmojiRow = -1; - reactionsStartRow = rowCount; - rowCount += visibleReactionsList.size(); - reactionsEndRow = rowCount; + oldItems.clear(); + oldItems.addAll(items); + items.clear(); + for (int i = 0; i < visibleReactionsList.size(); i++) { + items.add(new InnerItem(VIEW_TYPE_REACTION, visibleReactionsList.get(i))); + } if (showUnlockPremiumButton()) { - premiumUnlockButtonRow = rowCount++; + items.add(new InnerItem(VIEW_TYPE_PREMIUM_BUTTON, null)); } if (showCustomEmojiReaction()) { - customReactionsEmojiRow = rowCount++; + items.add(new InnerItem(VIEW_TYPE_CUSTOM_EMOJI_BUTTON, null)); } - super.notifyDataSetChanged(); + setItems(oldItems, items); + } + + class InnerItem extends AdapterWithDiffUtils.Item { + + ReactionsLayoutInBubble.VisibleReaction reaction; + + public InnerItem(int viewType, ReactionsLayoutInBubble.VisibleReaction reaction) { + super(viewType, false); + this.reaction = reaction; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InnerItem innerItem = (InnerItem) o; + if (viewType == innerItem.viewType && viewType == VIEW_TYPE_REACTION) { + return reaction != null && reaction.equals(innerItem.reaction); + } + return viewType == innerItem.viewType; + } + } }); recyclerListView.addOnScrollListener(new LeftRightShadowsListener()); @@ -439,7 +461,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio nextRecentReaction.getLayoutParams().height = size; bgPaint.setColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground, resourcesProvider)); - MediaDataController.getInstance(currentAccount).preloadReactions(); + MediaDataController.getInstance(currentAccount).preloadDefaultReactions(); } private void animatePullingBack() { @@ -462,21 +484,7 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio return; } reactionsWindow = new CustomEmojiReactionsWindow(fragment, allReactionsList, selectedReactions, this, resourcesProvider); - for (int i = 0; i < recyclerListView.getChildCount(); i++) { - View child = recyclerListView.getChildAt(i); - if (child instanceof ReactionHolderView) { - ReactionHolderView holderView = (ReactionHolderView) child; - if (holderView.loopImageView.getImageReceiver().getLottieAnimation() != null) { - holderView.loopImageView.getImageReceiver().moveLottieToFront(); - } - if (holderView.loopImageView.animatedEmojiDrawable != null) { - reactionsWindow.getSelectAnimatedEmojiDialog().putAnimatedEmojiToCache(holderView.loopImageView.animatedEmojiDrawable); - } - } - } - if (nextRecentReaction != null && nextRecentReaction.getVisibility() == View.VISIBLE) { - nextRecentReaction.loopImageView.getImageReceiver().moveLottieToFront(); - } + reactionsWindow.onDismissListener(() -> { reactionsWindow = null; }); @@ -1225,33 +1233,27 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio addView(enterImageView, LayoutHelper.createFrame(34, 34, Gravity.CENTER)); addView(pressedBackupImageView, LayoutHelper.createFrame(34, 34, Gravity.CENTER)); addView(loopImageView, LayoutHelper.createFrame(34, 34, Gravity.CENTER)); + enterImageView.setLayerNum(Integer.MAX_VALUE); + loopImageView.setLayerNum(Integer.MAX_VALUE); + pressedBackupImageView.setLayerNum(Integer.MAX_VALUE); } private void setReaction(ReactionsLayoutInBubble.VisibleReaction react, int position) { if (currentReaction != null && currentReaction.equals(react)) { + updateImage(react); return; } this.position = position; resetAnimation(); currentReaction = react; selected = selectedReactions.contains(react); - hasEnterAnimation = false;//currentReaction.emojicon != null && (!showCustomEmojiReaction() || allReactionsIsDefault); + hasEnterAnimation = currentReaction.emojicon != null && (!showCustomEmojiReaction() || allReactionsIsDefault); if (currentReaction.emojicon != null) { - TLRPC.TL_availableReaction defaultReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(currentReaction.emojicon); - if (defaultReaction != null) { - if (recyclerReaction) { - loopImageView.getImageReceiver().setUniqKeyPrefix("r"); - } - SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(defaultReaction.activate_animation, Theme.key_windowBackgroundGray, 1.0f); - enterImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.appear_animation), ReactionsUtils.APPEAR_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", react, 0); - pressedBackupImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", react, 0); - loopImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, hasEnterAnimation ? null : svgThumb, 0, "tgs", currentReaction, 0); - loopImageView.setAnimatedEmojiDrawable(null); + updateImage(react); - pressedBackupImageView.setAnimatedEmojiDrawable(null); - if (enterImageView.getImageReceiver().getLottieAnimation() != null) { - enterImageView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false); - } + pressedBackupImageView.setAnimatedEmojiDrawable(null); + if (enterImageView.getImageReceiver().getLottieAnimation() != null) { + enterImageView.getImageReceiver().getLottieAnimation().setCurrentFrame(0, false); } } else { pressedBackupImageView.getImageReceiver().clearImage(); @@ -1259,8 +1261,6 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio pressedBackupImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW_LARGE, currentAccount, currentReaction.documentId)); loopImageView.setAnimatedEmojiDrawable(new AnimatedEmojiDrawable(AnimatedEmojiDrawable.CACHE_TYPE_ALERT_PREVIEW, currentAccount, currentReaction.documentId)); } - enterImageView.setLayerNum(Integer.MAX_VALUE); - loopImageView.setLayerNum(Integer.MAX_VALUE); setFocusable(true); shouldSwitchToLoopView = hasEnterAnimation && showCustomEmojiReaction(); if (!hasEnterAnimation) { @@ -1281,6 +1281,18 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio } } + private void updateImage(ReactionsLayoutInBubble.VisibleReaction react) { + if (currentReaction.emojicon != null) { + TLRPC.TL_availableReaction defaultReaction = MediaDataController.getInstance(currentAccount).getReactionsMap().get(currentReaction.emojicon); + if (defaultReaction != null) { + SvgHelper.SvgDrawable svgThumb = DocumentObject.getSvgThumb(defaultReaction.activate_animation, Theme.key_windowBackgroundGray, 1.0f); + enterImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.appear_animation), ReactionsUtils.APPEAR_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", react, 0); + pressedBackupImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, svgThumb, 0, "tgs", react, 0); + loopImageView.getImageReceiver().setImage(ImageLocation.getForDocument(defaultReaction.select_animation), ReactionsUtils.SELECT_ANIMATION_FILTER, null, null, hasEnterAnimation ? null : svgThumb, 0, "tgs", currentReaction, 0); + } + } + } + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -1511,8 +1523,6 @@ public class ReactionsContainerLayout extends FrameLayout implements Notificatio public void play(int delay) { isEnter = true; -// cellFlickerDrawable.progress = 0; -// cellFlickerDrawable.repeatEnabled = false; invalidate(); if (valueAnimator != null) { valueAnimator.removeAllListeners(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java index 590e7c779..67bc8fc5c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -1899,6 +1899,10 @@ public class RecyclerListView extends RecyclerView { int emptyViewAnimateToVisibility; + public void checkIfEmpty() { + checkIfEmpty(updateEmptyViewAnimated()); + } + private void checkIfEmpty(boolean animated) { if (isHidden) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index fbb6ce640..a9ffbb63a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -434,7 +434,7 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie return false; } for (MessageObject obj : selectedFiles.values()) { - if (obj.getDocument() != null && obj.getDocument().size >= 500 * 1024 * 1024) { + if (obj.getDocument() != null && obj.getDocument().size >= 300 * 1024 * 1024) { return true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java index 0f2c4896b..880bb38ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java @@ -16,7 +16,6 @@ import android.view.MotionEvent; import android.view.View; import org.telegram.messenger.AndroidUtilities; -import org.telegram.ui.ActionBar.Theme; public class SeekBar { @@ -153,6 +152,9 @@ public class SeekBar { } public void setSize(int w, int h) { + if (width == w && height == h) { + return; + } width = w; height = h; setProgress(thumbProgress); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index ce74fedad..d5573e619 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -1723,7 +1723,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi topicsGridView.setScaleY(0.75f + value * 0.25f); topicsGridView.setAlpha(value); - RecyclerListView mainGridView = getMainGridView(); + RecyclerListView mainGridView = gridView; mainGridView.setPivotX(cell.getX() + cell.getWidth() / 2f); mainGridView.setPivotY(cell.getY() + cell.getHeight() / 2f); mainGridView.setScaleX(1f + value * 0.25f); @@ -1746,8 +1746,14 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi for (int i = 0; i < mainGridView.getChildCount(); i++) { View v = mainGridView.getChildAt(i); if (v instanceof ShareDialogCell) { - v.setTranslationX((v.getX() - cell.getX()) * 0.75f * moveValue); - v.setTranslationY((v.getY() - cell.getY()) * 0.75f * moveValue); + v.setTranslationX((v.getX() - cell.getX()) * 0.5f * moveValue); + v.setTranslationY((v.getY() - cell.getY()) * 0.5f * moveValue); + + if (v != cell) { + v.setAlpha(1f - Math.min(value, 0.5f) / 0.5f); + } else { + v.setAlpha(1f - value); + } } } for (int i = 0; i < topicsGridView.getChildCount(); i++) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index 2952bb529..71b64a1f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -534,8 +534,8 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter public SharedMediaPreloader(BaseFragment fragment) { parentFragment = fragment; - if (fragment instanceof FragmentContextView.ChatActivityInterface) { - FragmentContextView.ChatActivityInterface chatActivity = (FragmentContextView.ChatActivityInterface) fragment; + if (fragment instanceof ChatActivityInterface) { + ChatActivityInterface chatActivity = (ChatActivityInterface) fragment; dialogId = chatActivity.getDialogId(); mergeDialogId = chatActivity.getMergeDialogId(); topicId = chatActivity.getTopicId(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallRenderersContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallRenderersContainer.java index 0c2439df3..4e16e3fe6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallRenderersContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallRenderersContainer.java @@ -46,7 +46,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.AvatarsDarawable; +import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.AvatarsImageView; import org.telegram.ui.Components.CrossOutDrawable; import org.telegram.ui.Components.CubicBezierInterpolator; @@ -326,7 +326,7 @@ public class GroupCallRenderersContainer extends FrameLayout { }; speakingMembersAvatars = new AvatarsImageView(context, true); - speakingMembersAvatars.setStyle(AvatarsDarawable.STYLE_GROUP_CALL_TOOLTIP); + speakingMembersAvatars.setStyle(AvatarsDrawable.STYLE_GROUP_CALL_TOOLTIP); speakingMembersToast.setClipChildren(false); speakingMembersToast.setClipToPadding(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Delegates/ChatActivityMemberRequestsDelegate.java b/TMessagesProj/src/main/java/org/telegram/ui/Delegates/ChatActivityMemberRequestsDelegate.java index 42eee14e8..3f5ff5c4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Delegates/ChatActivityMemberRequestsDelegate.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Delegates/ChatActivityMemberRequestsDelegate.java @@ -3,7 +3,6 @@ package org.telegram.ui.Delegates; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; -import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.os.Build; @@ -81,7 +80,7 @@ public class ChatActivityMemberRequestsDelegate { avatarsView = new AvatarsImageView(fragment.getParentActivity(), false) { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = avatarsDarawable.count == 0 ? 0 : (20 * (avatarsDarawable.count - 1) + 24); + int width = avatarsDrawable.count == 0 ? 0 : (20 * (avatarsDrawable.count - 1) + 24); super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(width), MeasureSpec.EXACTLY), heightMeasureSpec); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index fcc238a7f..1b9d41053 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -86,7 +86,6 @@ import androidx.viewpager.widget.ViewPager; import org.telegram.messenger.AccountInstance; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.BotWebViewVibrationEffect; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; @@ -168,6 +167,7 @@ import org.telegram.ui.Components.FiltersListBottomSheet; import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.FloatingDebug.FloatingDebugController; import org.telegram.ui.Components.FloatingDebug.FloatingDebugProvider; +import org.telegram.ui.Components.Forum.ForumUtilities; import org.telegram.ui.Components.FragmentContextView; import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.LayoutHelper; @@ -3233,7 +3233,25 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. FileLog.e(e); } } - + + @Override + public void onButtonClicked(DialogCell dialogCell) { + if (dialogCell.getMessage() != null) { + TLRPC.TL_forumTopic topic = getMessagesController().getTopicsController().findTopic(-dialogCell.getDialogId(), MessageObject.getTopicId(dialogCell.getMessage().messageOwner)); + if (topic != null) { + if (onlySelect) { + didSelectResult(dialogCell.getDialogId(), topic.id, false, false); + } else { + ForumUtilities.openTopic(DialogsActivity.this, -dialogCell.getDialogId(), topic, 0); + } + } + } + } + + @Override + public void onButtonLongPress(DialogCell dialogCell) { + onItemLongClick(viewPage.listView, dialogCell, viewPage.listView.getChildAdapterPosition(dialogCell), 0, 0, viewPage.dialogsType, viewPage.dialogsAdapter); + } }; viewPage.dialogsAdapter.setForceShowEmptyCell(afterSignup); if (AndroidUtilities.isTablet() && openedDialogId != 0) { @@ -4292,13 +4310,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. public void updateSpeedItem(boolean visibleByPosition) { boolean visibleByDownload = false; for (MessageObject obj : getDownloadController().downloadingFiles) { - if (obj.getDocument() != null && obj.getDocument().size >= 500 * 1024 * 1024) { + if (obj.getDocument() != null && obj.getDocument().size >= 300 * 1024 * 1024) { visibleByDownload = true; break; } } for (MessageObject obj : getDownloadController().recentDownloadingFiles) { - if (obj.getDocument() != null && obj.getDocument().size >= 500 * 1024 * 1024) { + if (obj.getDocument() != null && obj.getDocument().size >= 300 * 1024 * 1024) { visibleByDownload = true; break; } @@ -4341,7 +4359,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } if (index != -1) { - FileLoader.getInstance(currentAccount).loadFile(premiumPromo.videos.get(index), null, FileLoader.PRIORITY_HIGH, 0); + FileLoader.getInstance(currentAccount).loadFile(premiumPromo.videos.get(index), premiumPromo, FileLoader.PRIORITY_HIGH, 0); } } } @@ -5436,6 +5454,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. return; } long dialogId = 0; + int topicId = 0; int message_id = 0; boolean isGlobalSearch = false; int folderId = 0; @@ -5527,6 +5546,10 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. MessageObject messageObject = (MessageObject) obj; dialogId = messageObject.getDialogId(); message_id = messageObject.getId(); + TLRPC.Chat chat = getMessagesController().getChat(-dialogId); + if (ChatObject.isForum(chat)) { + topicId = MessageObject.getTopicId(messageObject.messageOwner); + } searchViewPager.dialogsSearchAdapter.addHashtagsFromMessage(searchViewPager.dialogsSearchAdapter.getLastSearchString()); } else if (obj instanceof String) { String str = (String) obj; @@ -5640,10 +5663,13 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. slowedReloadAfterDialogClick = true; if (getMessagesController().checkCanOpenChat(args, DialogsActivity.this)) { TLRPC.Chat chat = getMessagesController().getChat(-dialogId); - if (chat != null && chat.forum) { + if (chat != null && chat.forum && topicId == 0) { presentFragment(new TopicsFragment(args)); } else { ChatActivity chatActivity = new ChatActivity(args); + if (topicId != 0) { + ForumUtilities.applyTopic(chatActivity, MessagesStorage.TopicKey.of(dialogId, topicId)); + } if (adapter instanceof DialogsAdapter && DialogObject.isUserDialog(dialogId) && (getMessagesController().dialogs_dict.get(dialogId) == null)) { TLRPC.Document sticker = getMediaDataController().getGreetingsSticker(); if (sticker != null) { @@ -5651,7 +5677,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } } presentFragment(chatActivity); - }; + } } } } @@ -8208,7 +8234,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else { continue; } - if (list == null) { + if (list == null || list.getAdapter() == null) { continue; } int count = list.getChildCount(); @@ -8227,7 +8253,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. cell.setChecked(false, (mask & MessagesController.UPDATE_MASK_CHAT) != 0); } else { if ((mask & MessagesController.UPDATE_MASK_NEW_MESSAGE) != 0) { - cell.checkCurrentDialogIndex(dialogsListFrozen); + if (cell.checkCurrentDialogIndex(dialogsListFrozen)) { + if (list.getAdapter() != null) { + list.getAdapter().notifyDataSetChanged(); + break; + } + } if (viewPages[c].isDefaultDialogType() && AndroidUtilities.isTablet()) { cell.setDialogSelected(cell.getDialogId() == openedDialogId); } @@ -8236,7 +8267,12 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. cell.setDialogSelected(cell.getDialogId() == openedDialogId); } } else { - cell.update(mask, animated); + if (cell.update(mask, animated)) { + if (list.getAdapter() != null) { + list.getAdapter().notifyDataSetChanged(); + break; + } + } } if (selectedDialogs != null) { cell.setChecked(selectedDialogs.contains(cell.getDialogId()), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index 3dbb83b5e..1c2da39e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -17,7 +17,6 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityNodeInfo; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -437,6 +436,7 @@ public class LanguageSelectActivity extends BaseFragment implements Notification ); showButtonCheck.setOnClickListener(e -> { preferences.edit().putBoolean("translate_button", !getValue()).apply(); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.updateSearchSettings); }); addView(showButtonCheck, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index f0b055627..c1f1140f5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -5907,6 +5907,7 @@ public class LaunchActivity extends BasePermissionsActivity implements INavigati if (drawerLayoutAdapter != null) { drawerLayoutAdapter.notifyDataSetChanged(); } + MessagesController.getMainSettings(currentAccount).edit().remove("transcribeButtonPressed").apply(); } else if (id == NotificationCenter.requestPermissions) { int type = (int) args[0]; String[] permissions = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index bc31e10d4..9a02e634d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -2126,15 +2126,18 @@ public class LoginActivity extends BaseFragment { for (int i = 0; i < help_countriesList.countries.size(); i++) { TLRPC.TL_help_country c = help_countriesList.countries.get(i); for (int k = 0; k < c.country_codes.size(); k++) { - CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); - countryWithCode.name = c.default_name; - countryWithCode.code = c.country_codes.get(k).country_code; - countryWithCode.shortname = c.iso2; + TLRPC.TL_help_countryCode countryCode = c.country_codes.get(k); + if (countryCode != null) { + CountrySelectActivity.Country countryWithCode = new CountrySelectActivity.Country(); + countryWithCode.name = c.default_name; + countryWithCode.code = countryCode.country_code; + countryWithCode.shortname = c.iso2; - countriesArray.add(countryWithCode); - codesMap.put(c.country_codes.get(k).country_code, countryWithCode); - if (c.country_codes.get(k).patterns.size() > 0) { - phoneFormatMap.put(c.country_codes.get(k).country_code, c.country_codes.get(k).patterns); + countriesArray.add(countryWithCode); + codesMap.put(countryCode.country_code, countryWithCode); + if (countryCode.patterns.size() > 0) { + phoneFormatMap.put(countryCode.country_code, countryCode.patterns); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LongPressListenerWithMovingGesture.java b/TMessagesProj/src/main/java/org/telegram/ui/LongPressListenerWithMovingGesture.java new file mode 100644 index 000000000..f9686d8a7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/LongPressListenerWithMovingGesture.java @@ -0,0 +1,141 @@ +package org.telegram.ui; + +import android.graphics.Rect; +import android.os.Build; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.ui.ActionBar.ActionBarPopupWindow; +import org.telegram.ui.Components.GestureDetector2; + + +public class LongPressListenerWithMovingGesture implements View.OnTouchListener { + + View view; + ActionBarPopupWindow submenu; + Rect rect = new Rect(); + boolean subItemClicked; + + GestureDetector2 gestureDetector2 = new GestureDetector2(new GestureDetector2.OnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + if (view != null) { + view.setPressed(true); + view.setSelected(true); + if (Build.VERSION.SDK_INT >= 21) { + if (Build.VERSION.SDK_INT == 21 && view.getBackground() != null) { + view.getBackground().setVisible(true, false); + } + view.drawableHotspotChanged(e.getX(), e.getY()); + } + } + return true; + } + + @Override + public void onUp(MotionEvent e) { + if (view != null) { + view.setPressed(false); + view.setSelected(false); + if (Build.VERSION.SDK_INT == 21 && view.getBackground() != null) { + view.getBackground().setVisible(false, false); + } + } + if (selectedMenuView != null && !subItemClicked) { + selectedMenuView.callOnClick(); + subItemClicked = true; + } + } + + @Override + public void onShowPress(MotionEvent e) { + + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + if (view != null) { + view.callOnClick(); + } + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + if (view != null) { + LongPressListenerWithMovingGesture.this.onLongPress(); + } + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + return false; + } + }); + + private int[] location = new int[2]; + private View selectedMenuView; + + public LongPressListenerWithMovingGesture() { + gestureDetector2.setIsLongpressEnabled(true); + } + + + @Override + public boolean onTouch(View v, MotionEvent event) { + view = v; + gestureDetector2.onTouchEvent(event); + if (submenu != null && !subItemClicked && event.getAction() == MotionEvent.ACTION_MOVE) { + view.getLocationOnScreen(location); + float x = event.getX() + location[0]; + float y = event.getY() + location[1]; + submenu.getContentView().getLocationOnScreen(location); + x -= location[0]; + y -= location[1]; + selectedMenuView = null; + ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout = (ActionBarPopupWindow.ActionBarPopupWindowLayout) submenu.getContentView(); + for (int a = 0; a < popupLayout.getItemsCount(); a++) { + View child = popupLayout.getItemAt(a); + child.getHitRect(rect); + Object tag = child.getTag(); + if (child.getVisibility() == View.VISIBLE && child.isClickable()) { + if (!rect.contains((int) x, (int) y)) { + child.setPressed(false); + child.setSelected(false); + if (Build.VERSION.SDK_INT == 21 && child.getBackground() != null) { + child.getBackground().setVisible(false, false); + } + } else { + child.setPressed(true); + child.setSelected(true); + if (Build.VERSION.SDK_INT >= 21) { + if (Build.VERSION.SDK_INT == 21 && child.getBackground() != null) { + child.getBackground().setVisible(true, false); + } + child.drawableHotspotChanged(x, y - child.getTop()); + } + selectedMenuView = child; + } + } + } + } + if (event.getAction() == MotionEvent.ACTION_UP && !subItemClicked && selectedMenuView != null) { + selectedMenuView.callOnClick(); + subItemClicked = true; + } + return true; + } + + public void setSubmenu(ActionBarPopupWindow actionBarPopupWindow) { + submenu = actionBarPopupWindow; + } + + public void onLongPress() { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java index e81d7a521..d45ab4a82 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageSeenView.java @@ -33,7 +33,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AvatarDrawable; -import org.telegram.ui.Components.AvatarsDarawable; +import org.telegram.ui.Components.AvatarsDrawable; import org.telegram.ui.Components.AvatarsImageView; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.FlickerLoadingView; @@ -74,7 +74,7 @@ public class MessageSeenView extends FrameLayout { addView(titleView, LayoutHelper.createFrame(0, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 40, 0, 0, 0)); avatarsImageView = new AvatarsImageView(context, false); - avatarsImageView.setStyle(AvatarsDarawable.STYLE_MESSAGE_SEEN); + avatarsImageView.setStyle(AvatarsDrawable.STYLE_MESSAGE_SEEN); avatarsImageView.setAvatarsTextSize(AndroidUtilities.dp(22)); addView(avatarsImageView, LayoutHelper.createFrame(24 + 12 + 12 + 8, LayoutHelper.MATCH_PARENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 30259518e..6f85a76f9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -3943,6 +3943,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private Bulletin.Delegate delegate = new Bulletin.Delegate() { @Override public int getBottomOffset(int tag) { + if (captionEditText.getVisibility() == View.GONE) { + return 0; + } return getHeight() - captionEditText.getTop(); } }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java index 58eb91a60..a64f7103c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PremiumPreviewFragment.java @@ -848,7 +848,7 @@ public class PremiumPreviewFragment extends BaseFragment implements Notification if (getMediaDataController().getPremiumPromo() != null) { for (TLRPC.Document document : getMediaDataController().getPremiumPromo().videos) { - FileLoader.getInstance(currentAccount).loadFile(document, null, FileLoader.PRIORITY_HIGH, 0); + FileLoader.getInstance(currentAccount).loadFile(document, getMediaDataController().getPremiumPromo(), FileLoader.PRIORITY_HIGH, 0); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index d70346126..edbb18b47 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -966,6 +966,7 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (!getUserConfig().isPremium()) { imageView.setVisibility(View.VISIBLE); imageView.setImageResource(R.drawable.msg_mini_premiumlock); + imageView.setTranslationY(AndroidUtilities.dp(1)); imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteValueText), PorterDuff.Mode.MULTIPLY)); } else { imageView.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_windowBackgroundWhiteGrayIcon), PorterDuff.Mode.MULTIPLY)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index 75fcd4137..17569d6b7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -165,6 +165,7 @@ import org.telegram.ui.Components.BackButtonMenu; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ChatActivityInterface; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.ChatNotificationsPopupWrapper; import org.telegram.ui.Components.CombinedDrawable; @@ -179,6 +180,7 @@ import org.telegram.ui.Components.IdenticonDrawable; import org.telegram.ui.Components.ImageUpdater; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.Premium.GiftPremiumBottomSheet; +import org.telegram.ui.Components.Premium.PremiumFeatureBottomSheet; import org.telegram.ui.Components.Premium.PremiumGradient; import org.telegram.ui.Components.Premium.PremiumPreviewBottomSheet; import org.telegram.ui.Components.Premium.ProfilePremiumCell; @@ -523,7 +525,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private String vcardFirstName; private String vcardLastName; - ChatActivity previousTransitionFragment; + ChatActivityInterface previousTransitionFragment; HashSet notificationsExceptionTopics = new HashSet<>(); @@ -748,12 +750,21 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. int y1 = (int) (v * (1.0f - mediaHeaderAnimationProgress)); if (y1 != 0) { - if (previousTransitionFragment != null) { + if (previousTransitionFragment != null && previousTransitionFragment.getContentView() != null) { AndroidUtilities.rectTmp2.set(0, 0, getMeasuredWidth(), y1); - previousTransitionFragment.contentView.drawBlurRect(canvas, getY(), AndroidUtilities.rectTmp2, previousTransitionFragment.getActionBar().blurScrimPaint, true); + previousTransitionFragment.getContentView().drawBlurRect(canvas, getY(), AndroidUtilities.rectTmp2, previousTransitionFragment.getActionBar().blurScrimPaint, true); } paint.setColor(currentColor); canvas.drawRect(0, 0, getMeasuredWidth(), y1, paint); + if (previousTransitionFragment != null) { + ActionBar actionBar = previousTransitionFragment.getActionBar(); + ActionBarMenu menu = actionBar.menu; + int restoreCount = canvas.save(); + canvas.translate(actionBar.getX() + menu.getX(), actionBar.getY() + menu.getY()); + canvas.saveLayerAlpha(0, 0, menu.getMeasuredWidth(), menu.getMeasuredHeight(), (int) (255 * (1f - animationProgress)), Canvas.ALL_SAVE_FLAG); + menu.draw(canvas); + canvas.restoreToCount(restoreCount); + } } if (y1 != v) { int color = getThemedColor(Theme.key_windowBackgroundWhite); @@ -1534,6 +1545,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().addObserver(this, NotificationCenter.didReceiveNewMessages); getNotificationCenter().addObserver(this, NotificationCenter.closeChats); getNotificationCenter().addObserver(this, NotificationCenter.topicsDidLoaded); + getNotificationCenter().addObserver(this, NotificationCenter.updateSearchSettings); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiLoaded); updateRowsIds(); if (listAdapter != null) { @@ -1596,6 +1608,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getNotificationCenter().removeObserver(this, NotificationCenter.closeChats); getNotificationCenter().removeObserver(this, NotificationCenter.didReceiveNewMessages); getNotificationCenter().removeObserver(this, NotificationCenter.topicsDidLoaded); + getNotificationCenter().removeObserver(this, NotificationCenter.updateSearchSettings); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiLoaded); if (avatarsViewPager != null) { avatarsViewPager.onDestroy(); @@ -1668,7 +1681,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. actionBar.setOccupyStatusBar(Build.VERSION.SDK_INT >= 21 && !AndroidUtilities.isTablet() && !inBubbleMode); ImageView backButton = actionBar.getBackButton(); backButton.setOnLongClickListener(e -> { - ActionBarPopupWindow menu = BackButtonMenu.show(this, backButton, getDialogId(), resourcesProvider); + ActionBarPopupWindow menu = BackButtonMenu.show(this, backButton, getDialogId(), getTopicId(), resourcesProvider); if (menu != null) { menu.setOnDismissListener(() -> dimBehindView(false)); dimBehindView(backButton, 0.3f); @@ -2237,6 +2250,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } + if (previousTransitionFragment != null) { + nameTextView[0].setRightPadding(nameTextView[0].getMeasuredWidth() - previousTransitionFragment.getAvatarContainer().getTitleTextView().getMeasuredWidth()); + } + if (!fragmentOpened && (expandPhoto || openAnimationInProgress && playProfileAnimation == 2)) { ignoreLayout = true; @@ -3392,11 +3409,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return false; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity(), resourcesProvider); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); + builder.setTitle(LocaleController.getString(R.string.ClearSearchAlertTitle)); + builder.setMessage(LocaleController.getString(R.string.ClearSearchAlert)); builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton), (dialogInterface, i) -> searchAdapter.clearRecent()); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + AlertDialog dialog = builder.create(); + showDialog(dialog); + TextView button = (TextView) dialog.getButton(DialogInterface.BUTTON_POSITIVE); + if (button != null) { + button.setTextColor(Theme.getColor(Theme.key_dialogTextRed2)); + } return true; }); searchListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @@ -4761,7 +4783,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private void leaveChatPressed() { - AlertsCreator.createClearOrDeleteDialogAlert(ProfileActivity.this, false, currentChat, null, false, false, true, (param) -> { + boolean isForum = ChatObject.isForum(currentChat); + AlertsCreator.createClearOrDeleteDialogAlert(ProfileActivity.this, false, currentChat, null, false, isForum, !isForum, (param) -> { playProfileAnimation = 0; getNotificationCenter().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); getNotificationCenter().postNotificationName(NotificationCenter.closeChats); @@ -5020,6 +5043,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. TLRPC.User user = users.get(a); getMessagesController().addUserToChat(chatId, user, fwdCount, null, ProfileActivity.this, () -> { if (++finished[0] == N) { + if (fragmentView == null || getParentActivity() == null) { + return; + } BulletinFactory.of(ProfileActivity.this).createUsersAddedBulletin(users, currentChat).show(); } }); @@ -5827,6 +5853,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (isTopic) { updateProfileData(false); } + } else if (id == NotificationCenter.updateSearchSettings) { + if (searchAdapter != null) { + searchAdapter.searchArray = searchAdapter.onCreateSearchArray(); + searchAdapter.recentSearches.clear(); + searchAdapter.updateSearchArray(); + searchAdapter.search(searchAdapter.lastSearchString); + } } } @@ -6133,8 +6166,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (parentLayout != null && parentLayout.getFragmentStack().size() >= 2) { BaseFragment fragment = parentLayout.getFragmentStack().get(parentLayout.getFragmentStack().size() - 2); - if (fragment instanceof ChatActivity) { - previousTransitionFragment = (ChatActivity) fragment; + if (fragment instanceof ChatActivityInterface) { + previousTransitionFragment = (ChatActivityInterface) fragment; + previousTransitionFragment.getAvatarContainer().getTitleTextView(); } } if (previousTransitionFragment != null) { @@ -6221,18 +6255,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } boolean onlineTextCrosafade = false; - BaseFragment previousFragment = parentLayout.getFragmentStack().size() > 1 ? parentLayout.getFragmentStack().get(parentLayout.getFragmentStack().size() - 2) : null; - if (previousFragment instanceof ChatActivity) { - ChatAvatarContainer avatarContainer = ((ChatActivity) previousFragment).getAvatarContainer(); - if (avatarContainer.getSubtitleTextView().getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { - transitionOnlineText = avatarContainer.getSubtitleTextView(); - avatarContainer2.invalidate(); - onlineTextCrosafade = true; - onlineTextView[0].setAlpha(0f); - onlineTextView[1].setAlpha(0f); - animators.add(ObjectAnimator.ofFloat(onlineTextView[1], View.ALPHA, 1.0f)); - } + + ChatAvatarContainer avatarContainer = ((ChatActivityInterface) previousTransitionFragment).getAvatarContainer(); + if (avatarContainer.getSubtitleTextView().getLeftDrawable() != null || avatarContainer.statusMadeShorter[0]) { + transitionOnlineText = avatarContainer.getSubtitleTextView(); + avatarContainer2.invalidate(); + onlineTextCrosafade = true; + onlineTextView[0].setAlpha(0f); + onlineTextView[1].setAlpha(0f); + animators.add(ObjectAnimator.ofFloat(onlineTextView[1], View.ALPHA, 1.0f)); } + if (!onlineTextCrosafade) { for (int a = 0; a < 2; a++) { onlineTextView[a].setAlpha(a == 0 ? 1.0f : 0.0f); @@ -6729,7 +6762,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (ChatObject.isChannel(currentChat)) { - if (!isTopic && chatInfo != null && currentChat.megagroup && chatInfo.participants != null && !chatInfo.participants.participants.isEmpty()) { + if (!isTopic && chatInfo != null && currentChat.megagroup && chatInfo.participants != null && chatInfo.participants.participants != null && !chatInfo.participants.participants.isEmpty()) { if (!ChatObject.isNotInChat(currentChat) && ChatObject.canAddUsers(currentChat) && chatInfo.participants_count < getMessagesController().maxMegagroupCount) { addMemberRow = rowCount++; } @@ -6772,7 +6805,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. lastSectionRow = rowCount++; } } else if (chatInfo != null) { - if (!isTopic && chatInfo.participants != null && !(chatInfo.participants instanceof TLRPC.TL_chatParticipantsForbidden)) { + if (!isTopic && chatInfo.participants != null && chatInfo.participants.participants != null && !(chatInfo.participants instanceof TLRPC.TL_chatParticipantsForbidden)) { if (ChatObject.canAddUsers(currentChat) || currentChat.default_banned_rights == null || !currentChat.default_banned_rights.invite_users) { addMemberRow = rowCount++; } @@ -7766,6 +7799,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (otherItem != null) { otherItem.setAlpha(progressHalf); } + if (qrItem != null) { + qrItem.setAlpha(progressHalf); + } searchItem.setAlpha(progressHalf); topView.invalidate(); fragmentView.invalidate(); @@ -8050,7 +8086,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. byte[] data = new byte[1024 * 64]; for (int i = 0; i < files.length; i++) { - if (last && (currentDate - files[i].lastModified()) > 24 * 60 * 60 * 1000) { + if ((last || files[i].getName().contains("_mtproto")) && (currentDate - files[i].lastModified()) > 24 * 60 * 60 * 1000) { continue; } FileInputStream fi = new FileInputStream(files[i]); @@ -8988,124 +9024,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } - private SearchResult[] searchArray = new SearchResult[]{ - new SearchResult(500, LocaleController.getString("EditName", R.string.EditName), 0, () -> presentFragment(new ChangeNameActivity(resourcesProvider))), - new SearchResult(501, LocaleController.getString("ChangePhoneNumber", R.string.ChangePhoneNumber), 0, () -> presentFragment(new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_CHANGE_PHONE_NUMBER))), - new SearchResult(502, LocaleController.getString("AddAnotherAccount", R.string.AddAnotherAccount), 0, () -> { - int freeAccount = -1; - for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { - if (!UserConfig.getInstance(a).isClientActivated()) { - freeAccount = a; - break; - } - } - if (freeAccount >= 0) { - presentFragment(new LoginActivity(freeAccount)); - } - }), - new SearchResult(503, LocaleController.getString("UserBio", R.string.UserBio), 0, () -> { - if (userInfo != null) { - presentFragment(new ChangeBioActivity()); - } - }), - - new SearchResult(1, LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(2, LocaleController.getString("NotificationsPrivateChats", R.string.NotificationsPrivateChats), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_PRIVATE, new ArrayList<>(), true))), - new SearchResult(3, LocaleController.getString("NotificationsGroups", R.string.NotificationsGroups), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_GROUP, new ArrayList<>(), true))), - new SearchResult(4, LocaleController.getString("NotificationsChannels", R.string.NotificationsChannels), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_CHANNEL, new ArrayList<>(), true))), - new SearchResult(5, LocaleController.getString("VoipNotificationSettings", R.string.VoipNotificationSettings), "callsSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(6, LocaleController.getString("BadgeNumber", R.string.BadgeNumber), "badgeNumberSection", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(7, LocaleController.getString("InAppNotifications", R.string.InAppNotifications), "inappSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(8, LocaleController.getString("ContactJoined", R.string.ContactJoined), "contactJoinedRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(9, LocaleController.getString("PinnedMessages", R.string.PinnedMessages), "pinnedMessageRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - new SearchResult(10, LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications), "resetNotificationsRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), - - new SearchResult(100, LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(101, LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyUsersActivity())), - new SearchResult(105, LocaleController.getString("PrivacyPhone", R.string.PrivacyPhone), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHONE, true))), - new SearchResult(102, LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN, true))), - new SearchResult(103, LocaleController.getString("PrivacyProfilePhoto", R.string.PrivacyProfilePhoto), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHOTO, true))), - new SearchResult(104, LocaleController.getString("PrivacyForwards", R.string.PrivacyForwards), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_FORWARDS, true))), - new SearchResult(122, LocaleController.getString("PrivacyP2P", R.string.PrivacyP2P), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_P2P, true))), - new SearchResult(106, LocaleController.getString("Calls", R.string.Calls), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_CALLS, true))), - new SearchResult(107, LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_INVITE, true))), - new SearchResult(123, LocaleController.getString("PrivacyVoiceMessages", R.string.PrivacyVoiceMessages), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> { - if (!getUserConfig().isPremium()) { - try { - fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); - } catch (Exception e) { - FileLog.e(e); - } - BulletinFactory.of(ProfileActivity.this).createRestrictVoiceMessagesPremiumBulletin().show(); - return; - } - presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_VOICE_MESSAGES, true)); - }), - new SearchResult(108, LocaleController.getString("Passcode", R.string.Passcode), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(PasscodeActivity.determineOpenFragment())), - new SearchResult(109, LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new TwoStepVerificationActivity())), - new SearchResult(110, LocaleController.getString("SessionsTitle", R.string.SessionsTitle), R.drawable.msg_secret, () -> presentFragment(new SessionsActivity(0))), - getMessagesController().autoarchiveAvailable ? new SearchResult(121, LocaleController.getString("ArchiveAndMute", R.string.ArchiveAndMute), "newChatsRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())) : null, - new SearchResult(112, LocaleController.getString("DeleteAccountIfAwayFor2", R.string.DeleteAccountIfAwayFor2), "deleteAccountRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(113, LocaleController.getString("PrivacyPaymentsClear", R.string.PrivacyPaymentsClear), "paymentsClearRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(114, LocaleController.getString("WebSessionsTitle", R.string.WebSessionsTitle), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new SessionsActivity(1))), - new SearchResult(115, LocaleController.getString("SyncContactsDelete", R.string.SyncContactsDelete), "contactsDeleteRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(116, LocaleController.getString("SyncContacts", R.string.SyncContacts), "contactsSyncRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(117, LocaleController.getString("SuggestContacts", R.string.SuggestContacts), "contactsSuggestRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(118, LocaleController.getString("MapPreviewProvider", R.string.MapPreviewProvider), "secretMapRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(119, LocaleController.getString("SecretWebPage", R.string.SecretWebPage), "secretWebpageRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), - new SearchResult(120, LocaleController.getString("Devices", R.string.Devices), R.drawable.msg_secret, () -> presentFragment(new SessionsActivity(0))), - - new SearchResult(200, LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(201, LocaleController.getString("DataUsage", R.string.DataUsage), "usageSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(202, LocaleController.getString("StorageUsage", R.string.StorageUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(203, LocaleController.getString("KeepMedia", R.string.KeepMedia), "keepMediaRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(204, LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), "cacheRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(205, LocaleController.getString("LocalDatabase", R.string.LocalDatabase), "databaseRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), - new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsageActivity())), - new SearchResult(207, LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload), "mediaDownloadSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(208, LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(0))), - new SearchResult(209, LocaleController.getString("WhenConnectedOnWiFi", R.string.WhenConnectedOnWiFi), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(1))), - new SearchResult(210, LocaleController.getString("WhenRoaming", R.string.WhenRoaming), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(2))), - new SearchResult(211, LocaleController.getString("ResetAutomaticMediaDownload", R.string.ResetAutomaticMediaDownload), "resetDownloadRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(212, LocaleController.getString("AutoplayMedia", R.string.AutoplayMedia), "autoplayHeaderRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(213, LocaleController.getString("AutoplayGIF", R.string.AutoplayGIF), "autoplayGifsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(214, LocaleController.getString("AutoplayVideo", R.string.AutoplayVideo), "autoplayVideoRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(215, LocaleController.getString("Streaming", R.string.Streaming), "streamSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(216, LocaleController.getString("EnableStreaming", R.string.EnableStreaming), "enableStreamRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(217, LocaleController.getString("Calls", R.string.Calls), "callsSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(218, LocaleController.getString("VoipUseLessData", R.string.VoipUseLessData), "useLessDataForCallsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(219, LocaleController.getString("VoipQuickReplies", R.string.VoipQuickReplies), "quickRepliesRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - new SearchResult(220, LocaleController.getString("ProxySettings", R.string.ProxySettings), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new ProxyListActivity())), - new SearchResult(221, LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), "callsRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("ProxySettings", R.string.ProxySettings), R.drawable.msg_data, () -> presentFragment(new ProxyListActivity())), - new SearchResult(111, LocaleController.getString("PrivacyDeleteCloudDrafts", R.string.PrivacyDeleteCloudDrafts), "clearDraftsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), - - new SearchResult(300, LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(301, LocaleController.getString("TextSizeHeader", R.string.TextSizeHeader), "textSizeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(302, LocaleController.getString("ChatBackground", R.string.ChatBackground), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), - new SearchResult(303, LocaleController.getString("SetColor", R.string.SetColor), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_COLOR))), - new SearchResult(304, LocaleController.getString("ResetChatBackgrounds", R.string.ResetChatBackgrounds), "resetRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), - new SearchResult(305, LocaleController.getString("AutoNightTheme", R.string.AutoNightTheme), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_NIGHT))), - new SearchResult(306, LocaleController.getString("ColorTheme", R.string.ColorTheme), "themeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(307, LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), "customTabsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(308, LocaleController.getString("DirectShare", R.string.DirectShare), "directShareRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(309, LocaleController.getString("EnableAnimations", R.string.EnableAnimations), "enableAnimationsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(310, LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), "raiseToSpeakRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(311, LocaleController.getString("SendByEnter", R.string.SendByEnter), "sendByEnterRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(312, LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings), "saveToGalleryRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(318, LocaleController.getString("DistanceUnits", R.string.DistanceUnits), "distanceRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), - new SearchResult(313, LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), - new SearchResult(314, LocaleController.getString("SuggestStickers", R.string.SuggestStickers), "suggestRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.msg_msgbubble3, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), - new SearchResult(315, LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.msg_msgbubble3, () -> presentFragment(new FeaturedStickersActivity())), - new SearchResult(316, LocaleController.getString("Masks", R.string.Masks), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.msg_msgbubble3, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_MASK, null))), - new SearchResult(317, LocaleController.getString("ArchivedStickers", R.string.ArchivedStickers), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.msg_msgbubble3, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_IMAGE))), - new SearchResult(317, LocaleController.getString("ArchivedMasks", R.string.ArchivedMasks), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("StickersAndMasks", R.string.StickersAndMasks), R.drawable.msg_msgbubble3, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_MASK))), - - new SearchResult(400, LocaleController.getString("Language", R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), - - new SearchResult(402, LocaleController.getString("AskAQuestion", R.string.AskAQuestion), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> showDialog(AlertsCreator.createSupportAlert(ProfileActivity.this, null))), - new SearchResult(403, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))), - new SearchResult(404, LocaleController.getString("PrivacyPolicy", R.string.PrivacyPolicy), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl))), - }; + private SearchResult[] searchArray = onCreateSearchArray(); private ArrayList faqSearchArray = new ArrayList<>(); private Context mContext; @@ -9122,6 +9041,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. public SearchAdapter(Context context) { mContext = context; + updateSearchArray(); + } + + private void updateSearchArray() { HashMap resultHashMap = new HashMap<>(); for (int a = 0; a < searchArray.length; a++) { if (searchArray[a] == null) { @@ -9174,6 +9097,183 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); } + private SearchResult[] onCreateSearchArray() { + return new SearchResult[]{ + new SearchResult(500, LocaleController.getString("EditName", R.string.EditName), 0, () -> presentFragment(new ChangeNameActivity(resourcesProvider))), + new SearchResult(501, LocaleController.getString("ChangePhoneNumber", R.string.ChangePhoneNumber), 0, () -> presentFragment(new ActionIntroActivity(ActionIntroActivity.ACTION_TYPE_CHANGE_PHONE_NUMBER))), + new SearchResult(502, LocaleController.getString("AddAnotherAccount", R.string.AddAnotherAccount), 0, () -> { + int freeAccount = -1; + for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { + if (!UserConfig.getInstance(a).isClientActivated()) { + freeAccount = a; + break; + } + } + if (freeAccount >= 0) { + presentFragment(new LoginActivity(freeAccount)); + } + }), + new SearchResult(503, LocaleController.getString("UserBio", R.string.UserBio), 0, () -> { + if (userInfo != null) { + presentFragment(new ChangeBioActivity()); + } + }), + new SearchResult(504, LocaleController.getString(R.string.AddPhoto), 0, ProfileActivity.this::onWriteButtonClick), + + new SearchResult(1, LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(2, LocaleController.getString("NotificationsPrivateChats", R.string.NotificationsPrivateChats), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_PRIVATE, new ArrayList<>(), true))), + new SearchResult(3, LocaleController.getString("NotificationsGroups", R.string.NotificationsGroups), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_GROUP, new ArrayList<>(), true))), + new SearchResult(4, LocaleController.getString("NotificationsChannels", R.string.NotificationsChannels), LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsCustomSettingsActivity(NotificationsController.TYPE_CHANNEL, new ArrayList<>(), true))), + new SearchResult(5, LocaleController.getString("VoipNotificationSettings", R.string.VoipNotificationSettings), "callsSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(6, LocaleController.getString("BadgeNumber", R.string.BadgeNumber), "badgeNumberSection", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(7, LocaleController.getString("InAppNotifications", R.string.InAppNotifications), "inappSectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(8, LocaleController.getString("ContactJoined", R.string.ContactJoined), "contactJoinedRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(9, LocaleController.getString("PinnedMessages", R.string.PinnedMessages), "pinnedMessageRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(10, LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications), "resetNotificationsRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(11, LocaleController.getString(R.string.NotificationsService), "notificationsServiceRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(12, LocaleController.getString(R.string.NotificationsServiceConnection), "notificationsServiceConnectionRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + new SearchResult(13, LocaleController.getString(R.string.RepeatNotifications), "repeatRow", LocaleController.getString("NotificationsAndSounds", R.string.NotificationsAndSounds), R.drawable.msg_notifications, () -> presentFragment(new NotificationsSettingsActivity())), + + new SearchResult(100, LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(101, LocaleController.getString("BlockedUsers", R.string.BlockedUsers), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyUsersActivity())), + new SearchResult(105, LocaleController.getString("PrivacyPhone", R.string.PrivacyPhone), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHONE, true))), + new SearchResult(102, LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_LASTSEEN, true))), + new SearchResult(103, LocaleController.getString("PrivacyProfilePhoto", R.string.PrivacyProfilePhoto), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_PHOTO, true))), + new SearchResult(104, LocaleController.getString("PrivacyForwards", R.string.PrivacyForwards), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_FORWARDS, true))), + new SearchResult(122, LocaleController.getString("PrivacyP2P", R.string.PrivacyP2P), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_P2P, true))), + new SearchResult(106, LocaleController.getString("Calls", R.string.Calls), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_CALLS, true))), + new SearchResult(107, LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_INVITE, true))), + new SearchResult(123, LocaleController.getString("PrivacyVoiceMessages", R.string.PrivacyVoiceMessages), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> { + if (!getUserConfig().isPremium()) { + try { + fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception e) { + FileLog.e(e); + } + BulletinFactory.of(ProfileActivity.this).createRestrictVoiceMessagesPremiumBulletin().show(); + return; + } + presentFragment(new PrivacyControlActivity(ContactsController.PRIVACY_RULES_TYPE_VOICE_MESSAGES, true)); + }), + new SearchResult(108, LocaleController.getString("Passcode", R.string.Passcode), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(PasscodeActivity.determineOpenFragment())), + new SearchResult(109, LocaleController.getString("TwoStepVerification", R.string.TwoStepVerification), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new TwoStepVerificationActivity())), + new SearchResult(110, LocaleController.getString("SessionsTitle", R.string.SessionsTitle), R.drawable.msg_secret, () -> presentFragment(new SessionsActivity(0))), + getMessagesController().autoarchiveAvailable ? new SearchResult(121, LocaleController.getString("ArchiveAndMute", R.string.ArchiveAndMute), "newChatsRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())) : null, + new SearchResult(112, LocaleController.getString("DeleteAccountIfAwayFor2", R.string.DeleteAccountIfAwayFor2), "deleteAccountRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(113, LocaleController.getString("PrivacyPaymentsClear", R.string.PrivacyPaymentsClear), "paymentsClearRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(114, LocaleController.getString("WebSessionsTitle", R.string.WebSessionsTitle), LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new SessionsActivity(1))), + new SearchResult(115, LocaleController.getString("SyncContactsDelete", R.string.SyncContactsDelete), "contactsDeleteRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(116, LocaleController.getString("SyncContacts", R.string.SyncContacts), "contactsSyncRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(117, LocaleController.getString("SuggestContacts", R.string.SuggestContacts), "contactsSuggestRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(118, LocaleController.getString("MapPreviewProvider", R.string.MapPreviewProvider), "secretMapRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + new SearchResult(119, LocaleController.getString("SecretWebPage", R.string.SecretWebPage), "secretWebpageRow", LocaleController.getString("PrivacySettings", R.string.PrivacySettings), R.drawable.msg_secret, () -> presentFragment(new PrivacySettingsActivity())), + + new SearchResult(120, LocaleController.getString(R.string.Devices), R.drawable.msg_devices, () -> presentFragment(new SessionsActivity(0))), + new SearchResult(121, LocaleController.getString(R.string.TerminateAllSessions), "terminateAllSessionsRow", LocaleController.getString(R.string.Devices), R.drawable.msg_devices, () -> presentFragment(new SessionsActivity(0))), + new SearchResult(122, LocaleController.getString(R.string.LinkDesktopDevice), LocaleController.getString(R.string.Devices), R.drawable.msg_devices, () -> presentFragment(new SessionsActivity(0).setHighlightLinkDesktopDevice())), + + new SearchResult(200, LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(201, LocaleController.getString("DataUsage", R.string.DataUsage), "usageSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(202, LocaleController.getString("StorageUsage", R.string.StorageUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), + new SearchResult(203, LocaleController.getString("KeepMedia", R.string.KeepMedia), "keepMediaRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), + new SearchResult(204, LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), "cacheRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), + new SearchResult(205, LocaleController.getString("LocalDatabase", R.string.LocalDatabase), "databaseRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("StorageUsage", R.string.StorageUsage), R.drawable.msg_data, () -> presentFragment(new CacheControlActivity())), + new SearchResult(206, LocaleController.getString("NetworkUsage", R.string.NetworkUsage), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataUsageActivity())), + new SearchResult(207, LocaleController.getString("AutomaticMediaDownload", R.string.AutomaticMediaDownload), "mediaDownloadSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(208, LocaleController.getString("WhenUsingMobileData", R.string.WhenUsingMobileData), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(0))), + new SearchResult(209, LocaleController.getString("WhenConnectedOnWiFi", R.string.WhenConnectedOnWiFi), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(1))), + new SearchResult(210, LocaleController.getString("WhenRoaming", R.string.WhenRoaming), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataAutoDownloadActivity(2))), + new SearchResult(211, LocaleController.getString("ResetAutomaticMediaDownload", R.string.ResetAutomaticMediaDownload), "resetDownloadRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(212, LocaleController.getString("AutoplayMedia", R.string.AutoplayMedia), "autoplayHeaderRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(213, LocaleController.getString("AutoplayGIF", R.string.AutoplayGIF), "autoplayGifsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(214, LocaleController.getString("AutoplayVideo", R.string.AutoplayVideo), "autoplayVideoRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(215, LocaleController.getString("Streaming", R.string.Streaming), "streamSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(216, LocaleController.getString("EnableStreaming", R.string.EnableStreaming), "enableStreamRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(217, LocaleController.getString("Calls", R.string.Calls), "callsSectionRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(218, LocaleController.getString("VoipUseLessData", R.string.VoipUseLessData), "useLessDataForCallsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(219, LocaleController.getString("VoipQuickReplies", R.string.VoipQuickReplies), "quickRepliesRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(220, LocaleController.getString("ProxySettings", R.string.ProxySettings), LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new ProxyListActivity())), + new SearchResult(221, LocaleController.getString("UseProxyForCalls", R.string.UseProxyForCalls), "callsRow", LocaleController.getString("DataSettings", R.string.DataSettings), LocaleController.getString("ProxySettings", R.string.ProxySettings), R.drawable.msg_data, () -> presentFragment(new ProxyListActivity())), + new SearchResult(111, LocaleController.getString("PrivacyDeleteCloudDrafts", R.string.PrivacyDeleteCloudDrafts), "clearDraftsRow", LocaleController.getString("DataSettings", R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(222, LocaleController.getString(R.string.SaveToGallery), "saveToGallerySectionRow", LocaleController.getString(R.string.DataSettings), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(223, LocaleController.getString(R.string.SaveToGalleryPrivate), "saveToGalleryPeerRow", LocaleController.getString(R.string.DataSettings), LocaleController.getString(R.string.SaveToGallery), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(224, LocaleController.getString(R.string.SaveToGalleryGroups), "saveToGalleryGroupsRow", LocaleController.getString(R.string.DataSettings), LocaleController.getString(R.string.SaveToGallery), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + new SearchResult(225, LocaleController.getString(R.string.SaveToGalleryChannels), "saveToGalleryChannelsRow", LocaleController.getString(R.string.DataSettings), LocaleController.getString(R.string.SaveToGallery), R.drawable.msg_data, () -> presentFragment(new DataSettingsActivity())), + + new SearchResult(300, LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(301, LocaleController.getString("TextSizeHeader", R.string.TextSizeHeader), "textSizeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(302, LocaleController.getString(R.string.ChangeChatBackground), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), + new SearchResult(303, LocaleController.getString("SetColor", R.string.SetColor), null, LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_COLOR))), + new SearchResult(304, LocaleController.getString("ResetChatBackgrounds", R.string.ResetChatBackgrounds), "resetRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), LocaleController.getString("ChatBackground", R.string.ChatBackground), R.drawable.msg_msgbubble3, () -> presentFragment(new WallpapersListActivity(WallpapersListActivity.TYPE_ALL))), + new SearchResult(306, LocaleController.getString("ColorTheme", R.string.ColorTheme), "themeHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(319, LocaleController.getString(R.string.BrowseThemes), null, LocaleController.getString(R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_THEMES_BROWSER))), + new SearchResult(320, LocaleController.getString(R.string.CreateNewTheme), "createNewThemeRow", LocaleController.getString(R.string.ChatSettings), LocaleController.getString(R.string.BrowseThemes), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_THEMES_BROWSER))), + new SearchResult(321, LocaleController.getString(R.string.BubbleRadius), "bubbleRadiusHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(322, LocaleController.getString(R.string.ChatList), "chatListHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(323, LocaleController.getString(R.string.ChatListSwipeGesture), "swipeGestureHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(324, LocaleController.getString(R.string.AppIcon), "appIconHeaderRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(305, LocaleController.getString("AutoNightTheme", R.string.AutoNightTheme), LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_NIGHT))), + new SearchResult(307, LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), "customTabsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(308, LocaleController.getString("DirectShare", R.string.DirectShare), "directShareRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(309, LocaleController.getString("EnableAnimations", R.string.EnableAnimations), "enableAnimationsRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(310, LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), "raiseToSpeakRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(325, LocaleController.getString(R.string.MicrophoneForVoiceMessages), "bluetoothScoRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + new SearchResult(311, LocaleController.getString("SendByEnter", R.string.SendByEnter), "sendByEnterRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + SharedConfig.canBlurChat() ? new SearchResult(326, LocaleController.getString(R.string.BlurInChat), "chatBlurRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))) : null, + new SearchResult(318, LocaleController.getString("DistanceUnits", R.string.DistanceUnits), "distanceRow", LocaleController.getString("ChatSettings", R.string.ChatSettings), R.drawable.msg_msgbubble3, () -> presentFragment(new ThemeActivity(ThemeActivity.THEME_TYPE_BASIC))), + + new SearchResult(600, LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), + new SearchResult(601, LocaleController.getString("SuggestStickers", R.string.SuggestStickers), "suggestRow", LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), + new SearchResult(602, LocaleController.getString("FeaturedStickers", R.string.FeaturedStickers), "featuredStickersHeaderRow", LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), + new SearchResult(603, LocaleController.getString("Masks", R.string.Masks), null, LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_MASK, null))), + new SearchResult(604, LocaleController.getString("ArchivedStickers", R.string.ArchivedStickers), null, LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_IMAGE))), + new SearchResult(605, LocaleController.getString("ArchivedMasks", R.string.ArchivedMasks), null, LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new ArchivedStickersActivity(MediaDataController.TYPE_MASK))), + new SearchResult(606, LocaleController.getString(R.string.LargeEmoji), "largeEmojiRow", LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), + new SearchResult(607, LocaleController.getString(R.string.LoopAnimatedStickers), "loopRow", LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_IMAGE, null))), + new SearchResult(608, LocaleController.getString(R.string.Emoji), null, LocaleController.getString(R.string.StickersName), R.drawable.input_smile, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, null))), + new SearchResult(609, LocaleController.getString(R.string.SuggestAnimatedEmoji), "suggestAnimatedEmojiRow", LocaleController.getString(R.string.StickersName), LocaleController.getString(R.string.Emoji), R.drawable.input_smile, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, null))), + new SearchResult(610, LocaleController.getString(R.string.FeaturedEmojiPacks), "featuredStickersHeaderRow", LocaleController.getString(R.string.StickersName), LocaleController.getString(R.string.Emoji), R.drawable.input_smile, () -> presentFragment(new StickersActivity(MediaDataController.TYPE_EMOJIPACKS, null))), + new SearchResult(611, LocaleController.getString(R.string.DoubleTapSetting), null, LocaleController.getString(R.string.StickersName), R.drawable.msg_sticker, () -> presentFragment(new ReactionsDoubleTapManageActivity())), + + new SearchResult(700, LocaleController.getString(R.string.Filters), null, R.drawable.msg_folder, () -> presentFragment(new FiltersSetupActivity())), + new SearchResult(701, LocaleController.getString(R.string.CreateNewFilter), "createFilterRow", LocaleController.getString(R.string.Filters), R.drawable.msg_folder, () -> presentFragment(new FiltersSetupActivity())), + + isPremiumFeatureAvailable(-1) ? new SearchResult(800, LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> presentFragment(new PremiumPreviewFragment("settings"))) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS) ? new SearchResult(801, LocaleController.getString(R.string.PremiumPreviewLimits), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_LIMITS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI) ? new SearchResult(802, LocaleController.getString(R.string.PremiumPreviewEmoji), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_EMOJI, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_UPLOAD_LIMIT) ? new SearchResult(803, LocaleController.getString(R.string.PremiumPreviewUploads), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_UPLOAD_LIMIT, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED) ? new SearchResult(804, LocaleController.getString(R.string.PremiumPreviewDownloadSpeed), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_DOWNLOAD_SPEED, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT) ? new SearchResult(805, LocaleController.getString(R.string.PremiumPreviewVoiceToText), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_VOICE_TO_TEXT, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_ADS) ? new SearchResult(806, LocaleController.getString(R.string.PremiumPreviewNoAds), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_ADS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS) ? new SearchResult(807, LocaleController.getString(R.string.PremiumPreviewReactions), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_REACTIONS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_STICKERS) ? new SearchResult(808, LocaleController.getString(R.string.PremiumPreviewStickers), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_STICKERS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT) ? new SearchResult(809, LocaleController.getString(R.string.PremiumPreviewAdvancedChatManagement), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_ADVANCED_CHAT_MANAGEMENT, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_PROFILE_BADGE) ? new SearchResult(810, LocaleController.getString(R.string.PremiumPreviewProfileBadge), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_PROFILE_BADGE, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS) ? new SearchResult(811, LocaleController.getString(R.string.PremiumPreviewAnimatedProfiles), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_ANIMATED_AVATARS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS) ? new SearchResult(812, LocaleController.getString(R.string.PremiumPreviewAppIcon), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_APPLICATION_ICONS, false).setForceAbout())) : null, + isPremiumFeatureAvailable(PremiumPreviewFragment.PREMIUM_FEATURE_EMOJI_STATUS) ? new SearchResult(813, LocaleController.getString(R.string.PremiumPreviewEmojiStatus), LocaleController.getString(R.string.TelegramPremium), R.drawable.msg_settings_premium, () -> showDialog(new PremiumFeatureBottomSheet(ProfileActivity.this, PremiumPreviewFragment.PREMIUM_FEATURE_EMOJI_STATUS, false).setForceAbout())) : null, + + new SearchResult(400, LocaleController.getString("Language", R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), + new SearchResult(405, LocaleController.getString(R.string.ShowTranslateButton), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())), + MessagesController.getGlobalMainSettings().getBoolean("translate_button", false) ? new SearchResult(406, LocaleController.getString(R.string.DoNotTranslate), LocaleController.getString(R.string.Language), R.drawable.msg_language, () -> presentFragment(new LanguageSelectActivity())) : null, + + new SearchResult(402, LocaleController.getString("AskAQuestion", R.string.AskAQuestion), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> showDialog(AlertsCreator.createSupportAlert(ProfileActivity.this, null))), + new SearchResult(403, LocaleController.getString("TelegramFAQ", R.string.TelegramFAQ), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))), + new SearchResult(404, LocaleController.getString("PrivacyPolicy", R.string.PrivacyPolicy), LocaleController.getString("SettingsHelp", R.string.SettingsHelp), R.drawable.msg_help, () -> Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl))), + }; + } + + private boolean isPremiumFeatureAvailable(int feature) { + if (getMessagesController().premiumLocked && !getUserConfig().isPremium()) { + return false; + } + + if (feature == -1) { + return true; + } + return getMessagesController().premiumFeaturesTypesToPosition.get(feature, -1) != -1; + } + private void loadFaqWebPage() { faqWebPage = getMessagesController().faqWebPage; if (faqWebPage != null) { @@ -9446,7 +9546,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (result.guid == 502) { int freeAccount = -1; for (int b = 0; b < UserConfig.MAX_ACCOUNT_COUNT; b++) { - if (!UserConfig.getInstance(a).isClientActivated()) { + if (!UserConfig.getInstance(b).isClientActivated()) { freeAccount = b; break; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java index 204e41584..56457176c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SelectAnimatedEmojiDialog.java @@ -2255,7 +2255,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati public int position; public TLRPC.Document document; public AnimatedEmojiSpan span; - public ImageReceiver.BackgroundThreadDrawHolder backgroundThreadDrawHolder; + public ImageReceiver.BackgroundThreadDrawHolder[] backgroundThreadDrawHolder = new ImageReceiver.BackgroundThreadDrawHolder[DrawingInBackgroundThreadDrawable.THREAD_COUNT]; public ImageReceiver imageReceiver; public ImageReceiver imageReceiverToDraw; public boolean isDefaultReaction; @@ -3283,8 +3283,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } else { imageReceiver.setRoundRadius(0); } - imageView.backgroundThreadDrawHolder = imageReceiver.setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder); - imageView.backgroundThreadDrawHolder.time = time; + imageView.backgroundThreadDrawHolder[threadIndex] = imageReceiver.setDrawInBackgroundThread(imageView.backgroundThreadDrawHolder[threadIndex], threadIndex); + imageView.backgroundThreadDrawHolder[threadIndex].time = time; imageView.imageReceiverToDraw = imageReceiver; imageView.update(time); @@ -3302,7 +3302,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati ); } AndroidUtilities.rectTmp2.offset(imageView.getLeft() + (int) imageView.getTranslationX() - startOffset, topOffset); - imageView.backgroundThreadDrawHolder.setBounds(AndroidUtilities.rectTmp2); + imageView.backgroundThreadDrawHolder[threadIndex].setBounds(AndroidUtilities.rectTmp2); imageView.skewAlpha = 1f; imageView.skewIndex = i; @@ -3326,7 +3326,7 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati } } else if (imageView.imageReceiverToDraw != null) { // imageView.drawable.setColorFilter(premiumStarColorFilter); - imageView.imageReceiverToDraw.draw(canvas, imageView.backgroundThreadDrawHolder); + imageView.imageReceiverToDraw.draw(canvas, imageView.backgroundThreadDrawHolder[threadIndex]); } } } @@ -3445,8 +3445,8 @@ public class SelectAnimatedEmojiDialog extends FrameLayout implements Notificati super.onFrameReady(); for (int i = 0; i < drawInBackgroundViews.size(); i++) { ImageViewEmoji imageView = drawInBackgroundViews.get(i); - if (imageView.backgroundThreadDrawHolder != null) { - imageView.backgroundThreadDrawHolder.release(); + if (imageView.backgroundThreadDrawHolder[threadIndex] != null) { + imageView.backgroundThreadDrawHolder[threadIndex].release(); } } emojiGridView.invalidate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java index c16ae456e..9684a50a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java @@ -13,6 +13,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Canvas; import android.net.Uri; import android.os.Build; import android.text.SpannableStringBuilder; @@ -73,6 +74,7 @@ import org.telegram.ui.Components.LinkSpanDrawable; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.UndoView; +import org.telegram.ui.Components.voip.CellFlickerDrawable; import java.util.ArrayList; import java.util.Objects; @@ -116,10 +118,18 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter private int repeatLoad = 0; + private boolean highlightLinkDesktopDevice; + private boolean fragmentOpened; + public SessionsActivity(int type) { currentType = type; } + public SessionsActivity setHighlightLinkDesktopDevice() { + this.highlightLinkDesktopDevice = true; + return this; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -135,6 +145,21 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.newSessionReceived); } + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + super.onTransitionAnimationEnd(isOpen, backward); + + if (isOpen && !backward) { + fragmentOpened = true; + for (int i = 0; i < listView.getChildCount(); i++) { + View ch = listView.getChildAt(i); + if (ch instanceof ScanQRCodeView) { + ((ScanQRCodeView) ch).buttonTextView.invalidate(); + } + } + } + } + @Override public View createView(Context context) { globalFlickerLoadingView = new FlickerLoadingView(context); @@ -902,12 +927,17 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter BackupImageView imageView; TextView textView; + TextView buttonTextView; + CellFlickerDrawable flickerDrawable = new CellFlickerDrawable(); public ScanQRCodeView(@NonNull Context context) { super(context); imageView = new BackupImageView(context); addView(imageView, LayoutHelper.createFrame(120, 120, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0)); + flickerDrawable.repeatEnabled = false; + flickerDrawable.animationSpeedScale = 1.2f; + imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { @@ -964,7 +994,19 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter textView.setText(spanned); - TextView buttonTextView = new TextView(context); + buttonTextView = new TextView(context) { + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (flickerDrawable.progress <= 1f && highlightLinkDesktopDevice && fragmentOpened) { + AndroidUtilities.rectTmp.set(0, 0, getWidth(), getHeight()); + flickerDrawable.setParentWidth(getMeasuredWidth()); + flickerDrawable.draw(canvas, AndroidUtilities.rectTmp, AndroidUtilities.dp(8), null); + invalidate(); + } + } + }; buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); buttonTextView.setGravity(Gravity.CENTER); buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java index 4b2a31db5..6bb01656e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsFragment.java @@ -39,6 +39,7 @@ import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -75,6 +76,7 @@ import org.telegram.ui.Components.AlertsCreator; import org.telegram.ui.Components.AnimatedEmojiDrawable; import org.telegram.ui.Components.Bulletin; import org.telegram.ui.Components.BulletinFactory; +import org.telegram.ui.Components.ChatActivityInterface; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.ChatNotificationsPopupWrapper; import org.telegram.ui.Components.ColoredImageSpan; @@ -87,6 +89,7 @@ import org.telegram.ui.Components.FragmentContextView; import org.telegram.ui.Components.InviteMembersBottomSheet; import org.telegram.ui.Components.JoinGroupAlert; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.RLottieImageView; import org.telegram.ui.Components.RadialProgressView; @@ -100,12 +103,11 @@ import org.telegram.ui.Delegates.ChatActivityMemberRequestsDelegate; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; -import java.util.Objects; -public class TopicsFragment extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, FragmentContextView.ChatActivityInterface { +public class TopicsFragment extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, ChatActivityInterface { final long chatId; - ArrayList forumTopics = new ArrayList<>(); + ArrayList forumTopics = new ArrayList<>(); SizeNotifierFrameLayout contentView; ChatAvatarContainer avatarContainer; @@ -124,6 +126,9 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N LinearLayoutManager layoutManager; boolean animatedUpdateEnabled = true; + private final static int VIEW_TYPE_TOPIC = 0; + private final static int VIEW_TYPE_LOADING_CELL = 1; + private static final int toggle_id = 1; private static final int add_member_id = 2; private static final int create_topic_id = 3; @@ -141,6 +146,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N boolean canShowCreateTopic; private UnreadCounterTextView bottomOverlayChatText; private RecyclerListView recyclerListView; + private ItemTouchHelper itemTouchHelper; private ActionBarMenuSubItem createTopicSubmenu; private ActionBarMenuSubItem addMemberSubMenu; private ActionBarMenuSubItem deleteChatSubmenu; @@ -149,6 +155,8 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private float searchAnimation2Progress = 0f; HashSet selectedTopics = new HashSet<>(); + private boolean reordering; + private boolean ignoreDiffUtil; private NumberTextView selectedDialogsCountTextView; private ActionBarMenuItem pinItem; private ActionBarMenuItem unpinItem; @@ -181,7 +189,6 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N DialogsActivity dialogsActivity; private boolean updateAnimated; - private long lastAnimatedDuration; private int transitionAnimationIndex; private int transitionAnimationGlobalIndex; @@ -418,6 +425,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N case delete_chat_id: TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); AlertsCreator.createClearOrDeleteDialogAlert(TopicsFragment.this, false, chatLocal, null, false, true, false, (param) -> { + getNotificationCenter().removeObserver(TopicsFragment.this, NotificationCenter.closeChats); getNotificationCenter().postNotificationName(NotificationCenter.closeChats); finishFragment(); getNotificationCenter().postNotificationName(NotificationCenter.needDeleteDialog, -chatLocal.id, null, chatLocal, param); @@ -433,7 +441,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N if (selectedTopics.size() > 0) { scrollToTop = true; updateAnimated = true; - topicsController.pinTopic(chatId, selectedTopics.iterator().next(), id == pin_id); + topicsController.pinTopic(chatId, selectedTopics.iterator().next(), id == pin_id, TopicsFragment.this); } clearSelectedTopics(); break; @@ -473,12 +481,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N actionBar.setOnClickListener(v -> { - Bundle args = new Bundle(); - args.putLong("chat_id", chatId); - ProfileActivity fragment = new ProfileActivity(args, avatarContainer.getSharedMediaPreloader()); -// fragment.setChatInfo(parentFragment.getCurrentChatInfo()); -// fragment.setPlayProfileAnimation(byAvatar ? 2 : 1); - presentFragment(fragment); + openProfile(false); }); ActionBarMenu menu = actionBar.createMenu(); @@ -522,14 +525,71 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N avatarContainer.setOccupyStatusBar(!AndroidUtilities.isTablet()); actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 86, 0)); + avatarContainer.getAvatarImageView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openProfile(true); + } + }); recyclerListView = new RecyclerListView(context) { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); checkForLoadMore(); } + + @Override + protected boolean emptyViewIsVisible() { + return super.emptyViewIsVisible(); + } + }; + DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator() { + Runnable finishRunnable; + int scrollAnimationIndex; + + @Override + public void checkIsRunning() { + if (scrollAnimationIndex == -1) { + scrollAnimationIndex = getNotificationCenter().setAnimationInProgress(scrollAnimationIndex, null, false); + if (finishRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(finishRunnable); + finishRunnable = null; + } + } + } + + @Override + protected void onAllAnimationsDone() { + super.onAllAnimationsDone(); + if (finishRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(finishRunnable); + finishRunnable = null; + } + AndroidUtilities.runOnUIThread(finishRunnable = () -> { + finishRunnable = null; + if (scrollAnimationIndex != -1) { + getNotificationCenter().onAnimationFinish(scrollAnimationIndex); + scrollAnimationIndex = -1; + } + }); + } + + + @Override + public void endAnimations() { + super.endAnimations(); + if (finishRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(finishRunnable); + } + AndroidUtilities.runOnUIThread(finishRunnable = () -> { + finishRunnable = null; + if (scrollAnimationIndex != -1) { + getNotificationCenter().onAnimationFinish(scrollAnimationIndex); + scrollAnimationIndex = -1; + } + }); + } }; - DefaultItemAnimator defaultItemAnimator = new DefaultItemAnimator(); defaultItemAnimator.setSupportsChangeAnimations(false); defaultItemAnimator.setDelayAnimations(false); recyclerListView.setItemAnimator(itemAnimator = defaultItemAnimator); @@ -541,7 +601,8 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } }); recyclerListView.setAnimateEmptyView(true, RecyclerListView.EMPTY_VIEW_ANIMATION_TYPE_ALPHA); - recyclerListView.setItemsEnterAnimator(itemsEnterAnimator = new RecyclerItemsEnterAnimator(recyclerListView, true)); + itemsEnterAnimator = new RecyclerItemsEnterAnimator(recyclerListView, true); + recyclerListView.setItemsEnterAnimator(itemsEnterAnimator); recyclerListView.setOnItemClickListener((view, position) -> { TLRPC.TL_forumTopic topic = null; if (view instanceof TopicDialogCell) { @@ -619,6 +680,8 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } } }); + itemTouchHelper = new ItemTouchHelper(new TouchHelperCallback()); + itemTouchHelper.attachToRecyclerView(recyclerListView); contentView.addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); ((ViewGroup.MarginLayoutParams) recyclerListView.getLayoutParams()).topMargin = -AndroidUtilities.dp(100); @@ -800,6 +863,15 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N return fragmentView; } + private void openProfile(boolean byAvatar) { + Bundle args = new Bundle(); + args.putLong("chat_id", chatId); + ProfileActivity fragment = new ProfileActivity(args, avatarContainer.getSharedMediaPreloader()); + fragment.setChatInfo(chatFull); + fragment.setPlayProfileAnimation(fragmentView.getMeasuredHeight() > fragmentView.getMeasuredWidth() && byAvatar ? 2 : 1); + presentFragment(fragment); + } + public void switchToChat(boolean removeFragment) { removeFragmentOnTransitionEnd = removeFragment; @@ -949,7 +1021,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N pinItem.setOnClickListener(e -> { scrollToTop = true; updateAnimated = true; - topicsController.pinTopic(chatId, topic.id, !topic.pinned); + topicsController.pinTopic(chatId, topic.id, !topic.pinned, TopicsFragment.this); finishPreviewFragment(); }); @@ -1022,6 +1094,9 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N if (topicsEmptyView != null && forumTopics.size() == 0) { topicsEmptyView.showProgress(loadingTopics, fragmentBeginToShow); } + if (recyclerListView != null) { + recyclerListView.checkIfEmpty(); + } updateCreateTopicButton(true); } @@ -1126,6 +1201,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N selectedTopics.clear(); actionBar.hideActionMode(); AndroidUtilities.updateVisibleRows(recyclerListView); + updateReordering(); } private void toggleSelection(View view) { @@ -1155,7 +1231,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } else { readCount++; } - if (ChatObject.canManageTopic(currentAccount, currentChat, topic)) { + if (ChatObject.canManageTopics(currentChat)) { if (topic.pinned) { canUnpinCount++; } else { @@ -1221,9 +1297,32 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N deleteItem.setVisibility(canDeleteCount == selectedTopics.size() ? View.VISIBLE : View.GONE); otherItem.checkHideMenuItem(); + + updateReordering(); } } + public void updateReordering() { + boolean canReorderPins = ChatObject.canManageTopics(getCurrentChat()); + boolean newReordering = canReorderPins && !selectedTopics.isEmpty(); + if (reordering != newReordering) { + reordering = newReordering; + adapter.notifyItemRangeChanged(0, adapter.getItemCount()); + } + } + + public void sendReorder() { + ArrayList newOrder = new ArrayList<>(); + for (int i = 0; i < forumTopics.size(); ++i) { + TLRPC.TL_forumTopic topic = forumTopics.get(i).topic; + if (topic != null && topic.pinned) { + newOrder.add(topic.id); + } + } + getMessagesController().getTopicsController().reorderPinnedTopics(chatId, newOrder); + ignoreDiffUtil = true; + } + private void chekActionMode() { if (actionBar.actionModeIsExist(null)) { return; @@ -1248,6 +1347,62 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N restartTopic = otherItem.addSubItem(restart_topic_id, R.drawable.msg_topic_restart, LocaleController.getString("RestartTopic", R.string.RestartTopic)); } + public class TouchHelperCallback extends ItemTouchHelper.Callback { + + @Override + public boolean isLongPressDragEnabled() { + return !selectedTopics.isEmpty(); + } + + @Override + public int getMovementFlags(@NonNull RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + int position = viewHolder.getAdapterPosition(); + if (position < 0 || position >= forumTopics.size() || forumTopics.get(position).topic == null || !forumTopics.get(position).topic.pinned) { + return makeMovementFlags(0, 0); + } + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } + int position = target.getAdapterPosition(); + if (position < 0 || position >= forumTopics.size() || forumTopics.get(position).topic == null || !forumTopics.get(position).topic.pinned) { + return false; + } + adapter.swapElements(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (actionState == ItemTouchHelper.ACTION_STATE_IDLE) { + sendReorder(); + } else { + recyclerListView.cancelClickRunnables(false); + viewHolder.itemView.setPressed(true); + } + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { + } + + @Override + public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + viewHolder.itemView.setPressed(false); + } + } + private void updateChatInfo() { updateChatInfo(false); } @@ -1262,6 +1417,11 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N if (!opnendForSelect) { if (chatLocal != null) { avatarContainer.setTitle(chatLocal.title); + Drawable rightIcon = null; + if (getMessagesController().isDialogMuted(-chatId, 0)) { + rightIcon = getThemedDrawable(Theme.key_drawable_muteIconDrawable); + } + avatarContainer.setTitleIcons(null, rightIcon); } updateSubtitle(); } else { @@ -1369,6 +1529,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.groupCallUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.notificationsSettingsUpdated); NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatSwithcedToForum); + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.closeChats); updateTopicsList(false, false); SelectAnimatedEmojiDialog.preload(currentAccount); @@ -1406,6 +1567,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.groupCallUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.notificationsSettingsUpdated); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatSwithcedToForum); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.closeChats); TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); if (ChatObject.isChannel(chatLocal)) { @@ -1416,43 +1578,40 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N private void updateTopicsList(boolean animated, boolean enalbeEnterAnimation) { - if (!animated && (updateAnimated || itemAnimator != null && (System.currentTimeMillis() - lastAnimatedDuration) < itemAnimator.getMoveDuration())) { + if (!animated && updateAnimated) { animated = true; } - if (animated) { - lastAnimatedDuration = System.currentTimeMillis(); - } updateAnimated = false; ArrayList topics = topicsController.getTopics(chatId); + if (topics != null) { int oldCount = forumTopics.size(); + ArrayList oldItems = new ArrayList<>(forumTopics); forumTopics.clear(); for (int i = 0; i < topics.size(); i++) { if (excludeTopics != null && excludeTopics.contains(topics.get(i).id)) { continue; } - forumTopics.add(topics.get(i)); + forumTopics.add(new Item(VIEW_TYPE_TOPIC, topics.get(i))); } - if (forumTopics.size() == 1 && forumTopics.get(0).id == 1) { + if (forumTopics.size() == 1 && forumTopics.get(0).topic.id == 1) { forumTopics.clear(); + } else if (!forumTopics.isEmpty() && !topicsController.endIsReached(chatId)) { + forumTopics.add(new Item(VIEW_TYPE_LOADING_CELL, null)); } - for (int i = forumTopics.size() - 1; i >= 0; --i) { - if (forumTopics.get(i).pinned) { - forumTopics.add(0, forumTopics.remove(i)); - } + int newCount = forumTopics.size(); + if (fragmentBeginToShow && enalbeEnterAnimation && newCount > oldCount) { + itemsEnterAnimator.showItemsAnimated(oldCount + 4); + animated = false; } + if (recyclerListView != null && recyclerListView.getItemAnimator() != (animated ? itemAnimator : null)) { recyclerListView.setItemAnimator(animated ? itemAnimator : null); } if (adapter != null) { - adapter.notifyDataSetChanged(true); - } - - int newCount = forumTopics.size(); - if (fragmentBeginToShow && enalbeEnterAnimation && newCount > oldCount) { - itemsEnterAnimator.showItemsAnimated(oldCount + 1); + adapter.setItems(oldItems, forumTopics); } if (scrollToTop && layoutManager != null) { @@ -1484,6 +1643,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N if (args.length > 1 && (Boolean) args[1]) { checkForLoadMore(); } + checkLoading(); } } else if (id == NotificationCenter.updateInterfaces) { int mask = (Integer) args[0]; @@ -1491,7 +1651,12 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N updateChatInfo(); } if ((mask & MessagesController.UPDATE_MASK_SELECT_DIALOG) > 0) { - updateTopicsList(false, false); + getMessagesController().getTopicsController().sortTopics(chatId, false); + boolean wasOnTop = !recyclerListView.canScrollVertically(-1); + updateTopicsList(true, false); + if (wasOnTop) { + layoutManager.scrollToPosition(0); + } } } else if (id == NotificationCenter.dialogsNeedReload) { updateTopicsList(false, false); @@ -1500,13 +1665,16 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N if (this.chatId == chatId) { groupCall = getMessagesController().getGroupCall(chatId, false); if (fragmentContextView != null) { - fragmentContextView.checkCall(true); + fragmentContextView.checkCall(!fragmentBeginToShow); } } } else if (id == NotificationCenter.notificationsSettingsUpdated) { updateTopicsList(false, false); + updateChatInfo(true); } else if (id == NotificationCenter.chatSwithcedToForum) { + } else if (id == NotificationCenter.closeChats) { + removeSelfFromStack(); } } @@ -1544,40 +1712,57 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N this.dialogsActivity = dialogsActivity; } - private class Adapter extends RecyclerListView.SelectionAdapter { + private class Adapter extends AdapterWithDiffUtils { + + @Override + public int getItemViewType(int position) { + return forumTopics.get(position).viewType; + } + @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - TopicDialogCell dialogCell = new TopicDialogCell(null, parent.getContext(), true, false); - return new RecyclerListView.Holder(dialogCell); + if (viewType == VIEW_TYPE_TOPIC) { + TopicDialogCell dialogCell = new TopicDialogCell(null, parent.getContext(), true, false); + return new RecyclerListView.Holder(dialogCell); + } else { + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(parent.getContext()); + flickerLoadingView.setViewType(FlickerLoadingView.TOPIC_CELL_TYPE); + flickerLoadingView.setIsSingleCell(true); + flickerLoadingView.showDate(true); + return new RecyclerListView.Holder(flickerLoadingView); + } } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - TLRPC.TL_forumTopic topic = forumTopics.get(position); - TLRPC.TL_forumTopic nextTopic = null; - if (position + 1 < forumTopics.size()) { - nextTopic = forumTopics.get(position + 1); + if (holder.getItemViewType() == VIEW_TYPE_TOPIC) { + TLRPC.TL_forumTopic topic = forumTopics.get(position).topic; + TLRPC.TL_forumTopic nextTopic = null; + if (position + 1 < forumTopics.size()) { + nextTopic = forumTopics.get(position + 1).topic; + } + TopicDialogCell dialogCell = (TopicDialogCell) holder.itemView; + + TLRPC.Message tlMessage = topic.topMessage; + int oldId = dialogCell.forumTopic == null ? 0 : dialogCell.forumTopic.id; + int newId = topic.id; + boolean animated = oldId == newId && dialogCell.position == position && animatedUpdateEnabled; + if (tlMessage != null) { + MessageObject messageObject = new MessageObject(currentAccount, tlMessage, false, false); + + dialogCell.setForumTopic(topic, -chatId, messageObject, animated); + dialogCell.drawDivider = position != forumTopics.size() - 1; + dialogCell.fullSeparator = topic.pinned && (nextTopic == null || !nextTopic.pinned); + dialogCell.setPinForced(topic.pinned); + dialogCell.position = position; + } + + dialogCell.setTopicIcon(topic); + + dialogCell.setChecked(selectedTopics.contains(newId), animated); + dialogCell.onReorderStateChanged(reordering, true); } - TopicDialogCell dialogCell = (TopicDialogCell) holder.itemView; - - TLRPC.Message tlMessage = topic.topMessage; - int oldId = dialogCell.forumTopic == null ? 0 : dialogCell.forumTopic.id; - int newId = topic.id; - boolean animated = oldId == newId && dialogCell.position == position && animatedUpdateEnabled; - if (tlMessage != null) { - MessageObject messageObject = new MessageObject(currentAccount, tlMessage, false, false); - - dialogCell.setForumTopic(topic, -chatId, messageObject, animated); - dialogCell.drawDivider = position != forumTopics.size() - 1; - dialogCell.fullSeparator = topic.pinned && (nextTopic == null || !nextTopic.pinned); - dialogCell.setPinForced(topic.pinned); - dialogCell.position = position; - } - - dialogCell.setTopicIcon(topic); - - dialogCell.setChecked(selectedTopics.contains(newId), animated); } @Override @@ -1587,52 +1772,15 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { - return true; + return holder.getItemViewType() == VIEW_TYPE_TOPIC; } - private ArrayList hashes = new ArrayList<>(); - - @Override - public void notifyDataSetChanged() { - hashes.clear(); - for (int i = 0; i < forumTopics.size(); ++i) { - hashes.add(forumTopics.get(i).id); - } - super.notifyDataSetChanged(); - } - - public void notifyDataSetChanged(boolean diff) { - final ArrayList oldHashes = new ArrayList<>(hashes); - hashes.clear(); - for (int i = 0; i < forumTopics.size(); ++i) { - hashes.add(forumTopics.get(i).id); - } - - if (diff) { - DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return oldHashes.size(); - } - - @Override - public int getNewListSize() { - return hashes.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return Objects.equals(hashes.get(newItemPosition), oldHashes.get(oldItemPosition)); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - return false; - } - }).dispatchUpdatesTo(this); - } else { - super.notifyDataSetChanged(); + public void swapElements(int from, int to) { + forumTopics.add(to, forumTopics.remove(from)); + if (recyclerListView.getItemAnimator() != itemAnimator) { + recyclerListView.setItemAnimator(itemAnimator); } + notifyItemMoved(from, to); } } @@ -1648,8 +1796,10 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N chekBoxPaddingTop = 24; heightDefault = 64; heightThreeLines = 76; + forbidVerified = true; } + private TLRPC.TL_forumTopic currentTopic; private AnimatedEmojiDrawable animatedEmojiDrawable; private Drawable forumIcon; boolean attached; @@ -1730,6 +1880,7 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } public void setTopicIcon(TLRPC.TL_forumTopic topic) { + currentTopic = topic; closed = topic != null && topic.closed; if (topic != null && topic.icon_emoji_id != 0) { setForumIcon(null); @@ -1959,9 +2110,9 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N String searchTrimmed = searchString.trim().toLowerCase(); ArrayList topics = new ArrayList<>(); for (int i = 0; i < forumTopics.size(); i++) { - if (forumTopics.get(i).title.toLowerCase().contains(searchTrimmed)) { - topics.add(forumTopics.get(i)); - forumTopics.get(i).searchQuery = searchTrimmed; + if (forumTopics.get(i).topic != null && forumTopics.get(i).topic.title.toLowerCase().contains(searchTrimmed)) { + topics.add(forumTopics.get(i).topic); + forumTopics.get(i).topic.searchQuery = searchTrimmed; } } @@ -2345,4 +2496,36 @@ public class TopicsFragment extends BaseFragment implements NotificationCenter.N } } } + + private class Item extends AdapterWithDiffUtils.Item { + + TLRPC.TL_forumTopic topic; + + public Item(int viewType, TLRPC.TL_forumTopic topic) { + super(viewType, true); + this.topic = topic; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; + if (viewType == item.viewType && viewType == VIEW_TYPE_TOPIC) { + return topic.id == item.topic.id; + } + return false; + + } + } + + @Override + public ChatAvatarContainer getAvatarContainer() { + return avatarContainer; + } + + @Override + public SizeNotifierFrameLayout getContentView() { + return contentView; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java b/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java index 7df9b62fd..7dcd35201 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TopicsNotifySettingsFragments.java @@ -10,7 +10,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DefaultItemAnimator; -import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -26,6 +25,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TopicExceptionCell; +import org.telegram.ui.Components.ListView.AdapterWithDiffUtils; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; @@ -100,7 +100,7 @@ public class TopicsNotifySettingsFragments extends BaseFragment { } if (items.get(position).viewType == VIEW_TYPE_TOPIC) { - TLRPC.TL_forumTopic topic = (TLRPC.TL_forumTopic) items.get(position).object; + TLRPC.TL_forumTopic topic = (TLRPC.TL_forumTopic) items.get(position).topic; Bundle bundle = new Bundle(); bundle.putLong("dialog_id", dialogId); bundle.putInt("topic_id", topic.id); @@ -199,32 +199,7 @@ public class TopicsNotifySettingsFragments extends BaseFragment { items.add(new Item(VIEW_TYPE_DIVIDER, null)); if (adapter != null) { - if (!animated) { - adapter.notifyDataSetChanged(); - } else { - ArrayList finalOldItems = oldItems; - DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return finalOldItems.size(); - } - - @Override - public int getNewListSize() { - return items.size(); - } - - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - return items.get(newItemPosition).compare(finalOldItems.get(oldItemPosition)); - } - - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - return false; - } - }).dispatchUpdatesTo(adapter); - } + adapter.setItems(oldItems, items); } } @@ -232,7 +207,7 @@ public class TopicsNotifySettingsFragments extends BaseFragment { exceptionsTopics = notificationsExceptionTopics; } - private class Adapter extends RecyclerListView.SelectionAdapter { + private class Adapter extends AdapterWithDiffUtils { @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -268,8 +243,8 @@ public class TopicsNotifySettingsFragments extends BaseFragment { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (items.get(position).viewType == VIEW_TYPE_TOPIC) { TopicExceptionCell cell = (TopicExceptionCell) holder.itemView; - cell.setTopic(dialogId, (TLRPC.TL_forumTopic) items.get(position).object); - cell.drawDivider = !(position != items.size() - 1 && items.get(position +1).viewType != VIEW_TYPE_TOPIC); + cell.setTopic(dialogId, items.get(position).topic); + cell.drawDivider = !(position != items.size() - 1 && items.get(position + 1).viewType != VIEW_TYPE_TOPIC); } } @@ -289,23 +264,26 @@ public class TopicsNotifySettingsFragments extends BaseFragment { } } - private class Item { - final int viewType; - final TLRPC.TL_forumTopic object; + private class Item extends AdapterWithDiffUtils.Item { + final TLRPC.TL_forumTopic topic; private Item(int viewType, TLRPC.TL_forumTopic object) { - this.viewType = viewType; - this.object = object; + super(viewType, false); + this.topic = object; } - boolean compare(Item item) { + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Item item = (Item) o; if (viewType != item.viewType) { return false; } - if (object != null && item.object != null && object.id == item.object.id) { - return true; + if (topic != null && item.topic != null) { + return topic.id == item.topic.id; } - return false; + return true; } } } diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_topicarrow.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_topicarrow.png new file mode 100644 index 000000000..d4b506f09 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_mini_topicarrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_viewchats.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_viewchats.png new file mode 100644 index 000000000..7a9bfb148 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_viewchats.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_topicarrow.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_topicarrow.png new file mode 100644 index 000000000..2a4f18e44 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_mini_topicarrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_viewchats.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_viewchats.png new file mode 100644 index 000000000..5db04eff1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_viewchats.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_topicarrow.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_topicarrow.png new file mode 100644 index 000000000..8ab3f334e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_mini_topicarrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_viewchats.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_viewchats.png new file mode 100644 index 000000000..8a160bd70 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_viewchats.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_topicarrow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_topicarrow.png new file mode 100644 index 000000000..6c6f8d318 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_mini_topicarrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_viewchats.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_viewchats.png new file mode 100644 index 000000000..8924ea30b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_viewchats.png differ diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 178db30c1..d716c6181 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -1662,8 +1662,10 @@ Your Username username Sorry, this username is already taken. + This link is already taken.\nHowever, it is currently available for purchase. **Learn more…** Sorry, this username is invalid. A username must have at least 5 characters. + A username must have at least 5 characters.\nHowever, it is currently available for purchase. **Learn more…** The username must not exceed 32 characters. Sorry, a username can\'t start with a number. You can choose a username on **Telegram**. If you do, other people will be able to find you by this username and contact you without knowing your phone number.\n\nYou can use **a–z**, **0–9** and underscores. Minimum length is **5** characters. @@ -3454,6 +3456,7 @@ Sorry, you are a member of too many groups and channels. For technical reasons, you need to leave some first before changing this setting in your groups. Sorry, the target user is a member of too many groups and channels. Please ask them to leave some first. + Sorry, you can\'t pin more than %d topics to the top. Warning! This will **delete all messages** in this chat for **both** participants. Warning! This will **delete all messages** in this channel. Warning! This will **delete all messages** in this chat. @@ -5696,6 +5699,7 @@ Reopen topic Close topics Reopen topics + All Topics View as topics Are you sure you want delete these topics? Are you sure you want delete %s? @@ -5776,4 +5780,5 @@ Make the caption shorter or subscribe to *Telegram Premium* to double the limit to **%1$s** characters. Make the caption shorter or subscribe to *Telegram Premium* to double the limit to **%1$s** characters. Make the caption shorter or subscribe to *Telegram Premium* to double the limit to **%1$s** characters. + All Chats diff --git a/gradle.properties b/gradle.properties index 780592585..fc2d4f3d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,8 +13,8 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true #Sat Mar 12 05:53:50 MSK 2016 -APP_VERSION_NAME=9.1.2 -APP_VERSION_CODE=2902 +APP_VERSION_NAME=9.1.3 +APP_VERSION_CODE=2917 APP_PACKAGE=org.telegram.messenger RELEASE_KEY_PASSWORD=TelegramAndroidPswd RELEASE_KEY_ALIAS=tmessages