From 6154c891bda4bc3651176b31463c9619a4793cba Mon Sep 17 00:00:00 2001 From: DrKLO Date: Sun, 6 Mar 2016 02:49:31 +0100 Subject: [PATCH] Update to 3.6.1 --- TMessagesProj/build.gradle | 4 +- TMessagesProj/jni/Android.mk | 2 +- TMessagesProj/jni/audio.c | 151 + TMessagesProj/jni/jni.c | 13 + TMessagesProj/jni/tgnet/Connection.cpp | 48 +- TMessagesProj/jni/tgnet/Connection.h | 11 + TMessagesProj/jni/tgnet/MTProtoScheme.cpp | 2 + TMessagesProj/jni/tgnet/MTProtoScheme.h | 3 +- TMessagesProj/src/main/AndroidManifest.xml | 14 +- .../telegram/messenger/AndroidUtilities.java | 32 + .../telegram/messenger/ApplicationLoader.java | 2 + .../org/telegram/messenger/BuildVars.java | 5 +- .../org/telegram/messenger/CallReceiver.java | 30 + .../telegram/messenger/ClearCacheService.java | 3 + .../messenger/ContactsController.java | 51 +- .../telegram/messenger/FileLoadOperation.java | 104 +- .../org/telegram/messenger/FileLoader.java | 172 +- .../org/telegram/messenger/ImageLoader.java | 46 +- .../org/telegram/messenger/ImageReceiver.java | 27 +- .../telegram/messenger/LocaleController.java | 24 + .../telegram/messenger/MediaController.java | 691 +++- .../org/telegram/messenger/MessageObject.java | 267 +- .../messenger/MessagesController.java | 603 +++- .../telegram/messenger/MessagesStorage.java | 333 +- .../messenger/MusicPlayerService.java | 58 +- .../org/telegram/messenger/NativeLoader.java | 2 +- .../messenger/NotificationCenter.java | 1 + .../messenger/NotificationsController.java | 157 +- .../telegram/messenger/SecretChatHelper.java | 841 ++--- .../messenger/SendMessagesHelper.java | 924 +++-- .../org/telegram/messenger/UserConfig.java | 8 +- .../org/telegram/messenger/Utilities.java | 1 + .../messenger/audioinfo/mp3/ID3v2Info.java | 2 +- .../messenger/query/MessagesSearchQuery.java | 3 + .../messenger/query/ReplyMessageQuery.java | 265 +- .../messenger/query/SharedMediaQuery.java | 18 +- .../messenger/query/StickersQuery.java | 88 +- .../telegram/tgnet/ConnectionsManager.java | 70 +- .../org/telegram/tgnet/NativeByteBuffer.java | 18 +- .../java/org/telegram/tgnet/TLClassStore.java | 34 +- .../main/java/org/telegram/tgnet/TLRPC.java | 2973 ++++++++++------- .../telegram/ui/ActionBar/BottomSheet.java | 1 + .../telegram/ui/Adapters/MentionsAdapter.java | 20 +- .../org/telegram/ui/AudioPlayerActivity.java | 2 +- .../org/telegram/ui/AudioSelectActivity.java | 3 +- .../org/telegram/ui/CacheControlActivity.java | 5 +- .../org/telegram/ui/Cells/AboutLinkCell.java | 7 +- .../org/telegram/ui/Cells/BotHelpCell.java | 7 +- .../org/telegram/ui/Cells/ChatAudioCell.java | 226 +- .../org/telegram/ui/Cells/ChatBaseCell.java | 153 +- .../telegram/ui/Cells/ChatContactCell.java | 30 +- .../org/telegram/ui/Cells/ChatMediaCell.java | 87 +- .../telegram/ui/Cells/ChatMessageCell.java | 35 +- .../org/telegram/ui/Cells/ChatMusicCell.java | 21 +- .../telegram/ui/Cells/ContextLinkCell.java | 4 +- .../org/telegram/ui/Cells/DialogCell.java | 12 +- .../org/telegram/ui/Cells/MentionCell.java | 3 + ...{LastSeenRadioCell.java => RadioCell.java} | 4 +- .../telegram/ui/Cells/SharedDocumentCell.java | 5 + .../org/telegram/ui/Cells/SharedLinkCell.java | 5 +- .../ui/Cells/SharedPhotoVideoCell.java | 15 +- .../org/telegram/ui/Cells/StickerCell.java | 53 + .../telegram/ui/Cells/StickerEmojiCell.java | 5 +- .../telegram/ui/ChannelCreateActivity.java | 2 +- .../org/telegram/ui/ChannelEditActivity.java | 174 +- .../org/telegram/ui/ChannelUsersActivity.java | 124 +- .../java/org/telegram/ui/ChatActivity.java | 789 +++-- .../telegram/ui/Components/AlertsCreator.java | 23 +- .../ui/Components/ChatActivityEnterView.java | 446 ++- .../ui/Components/ChatAttachView.java | 2 +- .../org/telegram/ui/Components/EmojiView.java | 267 +- .../ui/Components/FlowLayoutManager.java | 28 +- .../ui/Components/IdenticonDrawable.java | 43 +- .../telegram/ui/Components/PhotoCropView.java | 138 +- .../ui/Components/PhotoFilterBlurControl.java | 2 +- .../Components/PhotoFilterCurvesControl.java | 322 ++ .../ui/Components/PhotoFilterView.java | 1324 ++++++-- .../PhotoViewerCaptionEnterView.java | 17 +- .../telegram/ui/Components/PlayerView.java | 14 +- .../ui/Components/PopupAudioView.java | 21 +- .../telegram/ui/Components/RadioButton.java | 1 + .../java/org/telegram/ui/Components/Rect.java | 5 + .../ui/Components/ResourceLoader.java | 10 +- .../org/telegram/ui/Components/SeekBar.java | 6 +- .../ui/Components/SeekBarWaveform.java | 190 ++ .../ui/Components/ShareFrameLayout.java | 117 +- .../telegram/ui/Components/StickersAlert.java | 20 +- .../ui/Components/WebFrameLayout.java | 8 +- .../java/org/telegram/ui/DialogsActivity.java | 9 +- .../org/telegram/ui/GroupCreateActivity.java | 39 +- .../telegram/ui/GroupCreateFinalActivity.java | 6 +- .../org/telegram/ui/IdenticonActivity.java | 99 +- .../java/org/telegram/ui/IntroActivity.java | 4 +- .../java/org/telegram/ui/LaunchActivity.java | 146 +- .../org/telegram/ui/LocationActivity.java | 6 +- .../java/org/telegram/ui/LoginActivity.java | 28 +- .../java/org/telegram/ui/MediaActivity.java | 13 +- .../java/org/telegram/ui/PhotoViewer.java | 165 +- .../ui/PopupNotificationActivity.java | 5 + ...ivity.java => PrivacyControlActivity.java} | 136 +- .../telegram/ui/PrivacySettingsActivity.java | 90 +- ...ctivity.java => PrivacyUsersActivity.java} | 30 +- .../java/org/telegram/ui/ProfileActivity.java | 7 +- .../org/telegram/ui/SettingsActivity.java | 23 +- .../org/telegram/ui/StickerPreviewViewer.java | 189 +- .../res/drawable-hdpi/notify_members_off.png | Bin 0 -> 1729 bytes .../res/drawable-hdpi/notify_members_on.png | Bin 0 -> 1409 bytes .../src/main/res/drawable-hdpi/recorded.9.png | Bin 0 -> 690 bytes .../src/main/res/drawable-hdpi/s_pause.png | Bin 0 -> 975 bytes .../res/drawable-hdpi/s_pause_pressed.png | Bin 0 -> 975 bytes .../src/main/res/drawable-hdpi/s_play.png | Bin 0 -> 1178 bytes .../main/res/drawable-hdpi/s_play_pressed.png | Bin 0 -> 1190 bytes .../main/res/drawable-hdpi/tool_cropfix.png | Bin 0 -> 1018 bytes .../src/main/res/drawable-hdpi/tool_curve.png | Bin 0 -> 1137 bytes .../src/main/res/drawable-hdpi/tool_fade.png | Bin 0 -> 1372 bytes .../main/res/drawable-hdpi/tool_rotate.png | Bin 0 -> 1399 bytes .../src/main/res/drawable-hdpi/tool_tint.png | Bin 0 -> 1165 bytes .../res/drawable-mdpi/notify_members_off.png | Bin 0 -> 1500 bytes .../res/drawable-mdpi/notify_members_on.png | Bin 0 -> 1294 bytes .../src/main/res/drawable-mdpi/recorded.9.png | Bin 0 -> 460 bytes .../src/main/res/drawable-mdpi/s_pause.png | Bin 0 -> 965 bytes .../res/drawable-mdpi/s_pause_pressed.png | Bin 0 -> 969 bytes .../src/main/res/drawable-mdpi/s_play.png | Bin 0 -> 1034 bytes .../main/res/drawable-mdpi/s_play_pressed.png | Bin 0 -> 1081 bytes .../main/res/drawable-mdpi/tool_cropfix.png | Bin 0 -> 993 bytes .../src/main/res/drawable-mdpi/tool_curve.png | Bin 0 -> 1080 bytes .../src/main/res/drawable-mdpi/tool_fade.png | Bin 0 -> 1144 bytes .../main/res/drawable-mdpi/tool_rotate.png | Bin 0 -> 1174 bytes .../src/main/res/drawable-mdpi/tool_tint.png | Bin 0 -> 1123 bytes .../res/drawable-xhdpi/notify_members_off.png | Bin 0 -> 1793 bytes .../res/drawable-xhdpi/notify_members_on.png | Bin 0 -> 1542 bytes .../main/res/drawable-xhdpi/recorded.9.png | Bin 0 -> 841 bytes .../src/main/res/drawable-xhdpi/s_pause.png | Bin 0 -> 976 bytes .../res/drawable-xhdpi/s_pause_pressed.png | Bin 0 -> 985 bytes .../src/main/res/drawable-xhdpi/s_play.png | Bin 0 -> 1230 bytes .../res/drawable-xhdpi/s_play_pressed.png | Bin 0 -> 1245 bytes .../main/res/drawable-xhdpi/tool_cropfix.png | Bin 0 -> 1072 bytes .../main/res/drawable-xhdpi/tool_curve.png | Bin 0 -> 1247 bytes .../src/main/res/drawable-xhdpi/tool_fade.png | Bin 0 -> 1359 bytes .../main/res/drawable-xhdpi/tool_rotate.png | Bin 0 -> 1504 bytes .../src/main/res/drawable-xhdpi/tool_tint.png | Bin 0 -> 1288 bytes .../drawable-xxhdpi/notify_members_off.png | Bin 0 -> 2356 bytes .../res/drawable-xxhdpi/notify_members_on.png | Bin 0 -> 1801 bytes .../main/res/drawable-xxhdpi/recorded.9.png | Bin 0 -> 1412 bytes .../src/main/res/drawable-xxhdpi/s_pause.png | Bin 0 -> 992 bytes .../res/drawable-xxhdpi/s_pause_pressed.png | Bin 0 -> 1001 bytes .../src/main/res/drawable-xxhdpi/s_play.png | Bin 0 -> 1435 bytes .../res/drawable-xxhdpi/s_play_pressed.png | Bin 0 -> 1444 bytes .../main/res/drawable-xxhdpi/tool_cropfix.png | Bin 0 -> 1183 bytes .../main/res/drawable-xxhdpi/tool_curve.png | Bin 0 -> 1464 bytes .../main/res/drawable-xxhdpi/tool_fade.png | Bin 0 -> 1431 bytes .../main/res/drawable-xxhdpi/tool_rotate.png | Bin 0 -> 1824 bytes .../main/res/drawable-xxhdpi/tool_tint.png | Bin 0 -> 1503 bytes .../res/drawable/s_player_pause_states.xml | 6 + .../res/drawable/s_player_play_states.xml | 6 + .../src/main/res/layout/identicon_layout.xml | 46 - .../src/main/res/values-ar/strings.xml | 84 +- .../src/main/res/values-de/strings.xml | 78 +- .../src/main/res/values-es/strings.xml | 82 +- .../src/main/res/values-it/strings.xml | 84 +- .../src/main/res/values-ko/strings.xml | 82 +- .../src/main/res/values-nl/strings.xml | 78 +- .../src/main/res/values-pt-rBR/strings.xml | 88 +- .../src/main/res/values-pt-rPT/strings.xml | 88 +- TMessagesProj/src/main/res/values/strings.xml | 78 +- build.gradle | 2 +- 166 files changed, 10224 insertions(+), 4470 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java rename TMessagesProj/src/main/java/org/telegram/ui/Cells/{LastSeenRadioCell.java => RadioCell.java} (97%) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java rename TMessagesProj/src/main/java/org/telegram/ui/{LastSeenActivity.java => PrivacyControlActivity.java} (79%) rename TMessagesProj/src/main/java/org/telegram/ui/{LastSeenUsersActivity.java => PrivacyUsersActivity.java} (90%) create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/notify_members_on.png create mode 100644 TMessagesProj/src/main/res/drawable-hdpi/recorded.9.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/s_pause.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/s_play.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tool_curve.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/notify_members_off.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png create mode 100644 TMessagesProj/src/main/res/drawable-mdpi/recorded.9.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/s_pause.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/s_pause_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/s_play.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tool_curve.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/s_pause.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/s_play.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tool_fade.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_off.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png create mode 100644 TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/s_pause.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/s_pause_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/s_play_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tool_fade.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tool_rotate.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tool_tint.png create mode 100644 TMessagesProj/src/main/res/drawable/s_player_pause_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/s_player_play_states.xml delete mode 100644 TMessagesProj/src/main/res/layout/identicon_layout.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 37b1fb7b2..34a38990d 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -83,7 +83,7 @@ android { defaultConfig { minSdkVersion 9 targetSdkVersion 23 - versionCode 719 - versionName "3.4.2" + versionCode 755 + versionName "3.6.1" } } diff --git a/TMessagesProj/jni/Android.mk b/TMessagesProj/jni/Android.mk index 669fff9cc..995a53ee6 100755 --- a/TMessagesProj/jni/Android.mk +++ b/TMessagesProj/jni/Android.mk @@ -235,7 +235,7 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false -LOCAL_MODULE := tmessages.17 +LOCAL_MODULE := tmessages.19 LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS diff --git a/TMessagesProj/jni/audio.c b/TMessagesProj/jni/audio.c index 70b6e2fc2..87f946d4d 100644 --- a/TMessagesProj/jni/audio.c +++ b/TMessagesProj/jni/audio.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "utils.h" typedef struct { @@ -663,6 +664,156 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env result = error == OPUS_OK; } + if (pathStr != 0) { + (*env)->ReleaseStringUTFChars(env, path, pathStr); + } + + return result; +} + +static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t numBits, int32_t value) { + numBits = (unsigned int) (2 << (numBits - 1)) - 1; + bytes += bitOffset / 8; + bitOffset %= 8; + *((int32_t *) bytes) |= (value << bitOffset); +} + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JNIEnv *env, jclass class, jshortArray array, jint length) { + + jshort *sampleBuffer = (*env)->GetShortArrayElements(env, array, 0); + + jbyteArray result = 0; + int32_t resultSamples = 100; + uint16_t *samples = malloc(100 * 2); + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + int32_t sampleRate = (int32_t) max(1, length / resultSamples); + int index = 0; + + for (int i = 0; i < length; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + (*env)->ReleaseShortArrayElements(env, array, sampleBuffer, 0); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + + return result; +} + +int16_t *sampleBuffer = NULL; + + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) { + const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); + jbyteArray result = 0; + + int error = OPUS_OK; + OggOpusFile *opusFile = op_open_file(pathStr, &error); + if (opusFile != NULL && error == OPUS_OK) { + int64_t totalSamples = op_pcm_total(opusFile, -1); + int32_t resultSamples = 100; + int32_t sampleRate = (int32_t) max(1, totalSamples / resultSamples); + + uint16_t *samples = malloc(100 * 2); + + int bufferSize = 1024 * 128; + if (sampleBuffer == NULL) { + sampleBuffer = malloc(bufferSize); + } + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + + int index = 0; + + while (1) { + int readSamples = op_read(opusFile, sampleBuffer, bufferSize / 2, NULL); + for (int i = 0; i < readSamples; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + if (readSamples == 0) { + break; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + //free(sampleBuffer); + op_free(opusFile); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + } + + + if (pathStr != 0) { (*env)->ReleaseStringUTFChars(env, path, pathStr); } diff --git a/TMessagesProj/jni/jni.c b/TMessagesProj/jni/jni.c index f300f8e71..2b17fd617 100644 --- a/TMessagesProj/jni/jni.c +++ b/TMessagesProj/jni/jni.c @@ -59,3 +59,16 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en (*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0); } + +JNIEXPORT jstring Java_org_telegram_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) { + static char buf[1000]; + char *fileName = (*env)->GetStringUTFChars(env, path, NULL); + int result = readlink(fileName, buf, 999); + jstring value = 0; + if (result != -1) { + buf[result] = '\0'; + value = (*env)->NewStringUTF(env, buf); + } + (*env)->ReleaseStringUTFChars(env, path, fileName); + return value; +} diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp index 16a544f25..3a9e7a3af 100644 --- a/TMessagesProj/jni/tgnet/Connection.cpp +++ b/TMessagesProj/jni/tgnet/Connection.cpp @@ -6,6 +6,8 @@ * Copyright Nikolai Kudashov, 2015. */ +#include +#include #include "Connection.h" #include "ConnectionsManager.h" #include "BuffersStorage.h" @@ -55,6 +57,8 @@ void Connection::suspendConnection() { } void Connection::onReceivedData(NativeByteBuffer *buffer) { + //AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum); + failedConnectionCount = 0; NativeByteBuffer *parseLaterBuffer = nullptr; @@ -305,12 +309,47 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) { bufferLen += 4; } if (!firstPacketSent) { - bufferLen++; + bufferLen += 64; } NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(bufferLen); + uint8_t *bytes = buffer->bytes(); + if (!firstPacketSent) { - buffer->writeByte(0xef); + buffer->position(64); + static uint8_t temp[64]; + while (true) { + RAND_bytes(bytes, 64); + uint32_t val = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0]); + uint32_t val2 = (bytes[7] << 24) | (bytes[6] << 16) | (bytes[5] << 8) | (bytes[4]); + if (bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val2 != 0x00000000) { + //bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef; + break; + } + } + /*for (int a = 0; a < 48; a++) { + temp[a] = bytes[55 - a]; + } + + encryptNum = decryptNum = 0; + memset(encryptCount, 0, 16); + memset(decryptCount, 0, 16); + + if (AES_set_encrypt_key(bytes + 8, 256, &encryptKey) < 0) { + DEBUG_E("unable to set encryptKey"); + exit(1); + } + memcpy(encryptIv, bytes + 40, 16); + + if (AES_set_encrypt_key(temp, 256, &decryptKey) < 0) { + DEBUG_E("unable to set decryptKey"); + exit(1); + } + memcpy(decryptIv, temp + 32, 16); + + AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum); + memcpy(bytes + 56, temp + 56, 8);*/ + firstPacketSent = true; } if (packetLength < 0x7f) { @@ -318,17 +357,22 @@ void Connection::sendData(NativeByteBuffer *buff, bool reportAck) { packetLength |= (1 << 7); } buffer->writeByte((uint8_t) packetLength); + bytes += (buffer->limit() - 1); + //AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum); } else { packetLength = (packetLength << 8) + 0x7f; if (reportAck) { packetLength |= (1 << 7); } buffer->writeInt32(packetLength); + bytes += (buffer->limit() - 4); + //AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum); } buffer->rewind(); writeBuffer(buffer); buff->rewind(); + //AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum); writeBuffer(buff); } diff --git a/TMessagesProj/jni/tgnet/Connection.h b/TMessagesProj/jni/tgnet/Connection.h index 372567fa6..76da54f4f 100644 --- a/TMessagesProj/jni/tgnet/Connection.h +++ b/TMessagesProj/jni/tgnet/Connection.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "ConnectionSession.h" #include "ConnectionSocket.h" #include "Defines.h" @@ -67,6 +68,16 @@ private: bool wasConnected = false; uint32_t willRetryConnectCount = 5; Timer *reconnectTimer; + + AES_KEY encryptKey; + uint8_t encryptIv[16]; + uint32_t encryptNum; + uint8_t encryptCount[16]; + + AES_KEY decryptKey; + uint8_t decryptIv[16]; + uint32_t decryptNum; + uint8_t decryptCount[16]; friend class ConnectionsManager; }; diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.cpp b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp index a88f591e4..7921031dc 100644 --- a/TMessagesProj/jni/tgnet/MTProtoScheme.cpp +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp @@ -946,6 +946,7 @@ void TL_config::readParams(NativeByteBuffer *stream, bool &error) { push_chat_period_ms = stream->readInt32(&error); push_chat_limit = stream->readInt32(&error); saved_gifs_limit = stream->readInt32(&error); + edit_time_limit = stream->readInt32(&error); magic = stream->readUint32(&error); if (magic != 0x1cb5c415) { error = true; @@ -987,6 +988,7 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) { stream->writeInt32(push_chat_period_ms); stream->writeInt32(push_chat_limit); stream->writeInt32(saved_gifs_limit); + stream->writeInt32(edit_time_limit); stream->writeInt32(0x1cb5c415); count = (uint32_t) disabled_features.size(); stream->writeInt32(count); diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.h b/TMessagesProj/jni/tgnet/MTProtoScheme.h index e6e399bd3..75922fefc 100644 --- a/TMessagesProj/jni/tgnet/MTProtoScheme.h +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.h @@ -657,7 +657,7 @@ public: class TL_config : public TLObject { public: - static const uint32_t constructor = 0x6bbc5f8; + static const uint32_t constructor = 0x317ceef4; int32_t date; int32_t expires; @@ -677,6 +677,7 @@ public: int32_t push_chat_period_ms; int32_t push_chat_limit; int32_t saved_gifs_limit; + int32_t edit_time_limit; std::vector> disabled_features; static TL_config *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 74e63fcda..d73a9affa 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -129,18 +129,28 @@ android:windowSoftInputMode="adjustResize|stateHidden"> - + - + + + + + + + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index 370175048..c0dece7b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -27,6 +27,8 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Environment; +import android.os.Parcelable; +import android.provider.Browser; import android.provider.DocumentsContract; import android.provider.MediaStore; import android.text.Spannable; @@ -409,6 +411,29 @@ public class AndroidUtilities { } } + public static void openUrl(Context context, String url) { + if (context == null || url == null) { + return; + } + openUrl(context, Uri.parse(url)); + } + + public static void openUrl(Context context, Uri uri) { + if (context == null || uri == null) { + return; + } + try { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.putExtra("android.support.customtabs.extra.SESSION", (Parcelable) null); + intent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", 0xff54759e); + intent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", 1); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + context.startActivity(intent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + public static int getPhotoSize() { if (photoSize == null) { if (Build.VERSION.SDK_INT >= 16) { @@ -1057,4 +1082,11 @@ public class AndroidUtilities { } return true; } + + public static byte[] calcAuthKeyHash(byte[] auth_key) { + byte[] sha1 = Utilities.computeSHA1(auth_key); + byte[] key_hash = new byte[16]; + System.arraycopy(sha1, 0, key_hash, 0, 16); + return key_hash; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index 3babf6e3a..e511f2b16 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -325,6 +325,8 @@ public class ApplicationLoader extends Application { FileLog.d("tmessages", "GCM Registration not found."); Intent intent = new Intent(applicationContext, GcmRegistrationIntentService.class); startService(intent); + } else { + FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString); } } else { FileLog.d("tmessages", "No valid Google Play Services APK found."); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java index 771ff364c..561857a6c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuildVars.java @@ -3,14 +3,15 @@ * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * - * Copyright Nikolai Kudashov, 2013-2015. + * Copyright Nikolai Kudashov, 2013-2016. */ package org.telegram.messenger; public class BuildVars { public static boolean DEBUG_VERSION = false; - public static int BUILD_VERSION = 719; + public static int BUILD_VERSION = 753; + public static String BUILD_VERSION_STRING = "3.6"; public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id public static String APP_HASH = ""; //obtain your own APP_HASH at https://core.telegram.org/api/obtaining_api_id public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java new file mode 100644 index 000000000..2aae70ab0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java @@ -0,0 +1,30 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class CallReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, Intent intent) { + /*TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + telephony.listen(new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + super.onCallStateChanged(state, incomingNumber); + if (state == 1 && incomingNumber != null && incomingNumber.length() > 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, incomingNumber); + } + } + }, PhoneStateListener.LISTEN_CALL_STATE);*/ + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java index 39d1a438e..044f80dcc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java @@ -48,6 +48,9 @@ public class ClearCacheService extends IntentService { for (int b = 0; b < array.length; b++) { File f = array[b]; if (f.isFile()) { + if (f.getName().equals(".nomedia")) { + continue; + } if (Build.VERSION.SDK_INT >= 21) { try { StructStat stat = Os.stat(f.getPath()); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index 676f20358..4831c12b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -56,7 +56,9 @@ public class ContactsController { private int loadingDeleteInfo = 0; private int deleteAccountTTL; private int loadingLastSeenInfo = 0; + private int loadingGroupInfo = 0; private ArrayList privacyRules = null; + private ArrayList groupPrivacyRules = null; public static class Contact { public int id; @@ -160,6 +162,7 @@ public class ContactsController { loadingDeleteInfo = 0; deleteAccountTTL = 0; loadingLastSeenInfo = 0; + loadingGroupInfo = 0; privacyRules = null; } @@ -177,8 +180,8 @@ public class ContactsController { ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response; + if (response != null) { + final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText) response; if (res.message.length() != 0) { AndroidUtilities.runOnUIThread(new Runnable() { @Override @@ -1859,6 +1862,30 @@ public class ContactsController { } }); } + if (loadingGroupInfo == 0) { + loadingGroupInfo = 1; + TLRPC.TL_account_getPrivacy req = new TLRPC.TL_account_getPrivacy(); + req.key = new TLRPC.TL_inputPrivacyKeyChatInvite(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; + MessagesController.getInstance().putUsers(rules.users, false); + groupPrivacyRules = rules.rules; + loadingGroupInfo = 2; + } else { + loadingGroupInfo = 0; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + }); + } + }); + } NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); } @@ -1878,12 +1905,24 @@ public class ContactsController { return loadingLastSeenInfo != 2; } - public ArrayList getPrivacyRules() { - return privacyRules; + public boolean getLoadingGroupInfo() { + return loadingGroupInfo != 2; } - public void setPrivacyRules(ArrayList rules) { - privacyRules = rules; + public ArrayList getPrivacyRules(boolean isGroup) { + if (isGroup) { + return groupPrivacyRules; + } else { + return privacyRules; + } + } + + public void setPrivacyRules(ArrayList rules, boolean isGroup) { + if (isGroup) { + groupPrivacyRules = rules; + } else { + privacyRules = rules; + } NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); reloadContactsStatuses(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 294314cdb..420b76718 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -94,73 +94,59 @@ public class FileLoadOperation { ext = extension != null ? extension : "jpg"; } - public FileLoadOperation(TLRPC.Video videoLocation) { - if (videoLocation instanceof TLRPC.TL_videoEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = videoLocation.id; - location.access_hash = videoLocation.access_hash; - datacenter_id = videoLocation.dc_id; - iv = new byte[32]; - System.arraycopy(videoLocation.iv, 0, iv, 0, iv.length); - key = videoLocation.key; - } else if (videoLocation instanceof TLRPC.TL_video) { - location = new TLRPC.TL_inputVideoFileLocation(); - datacenter_id = videoLocation.dc_id; - location.id = videoLocation.id; - location.access_hash = videoLocation.access_hash; - } - totalBytesCount = videoLocation.size; - ext = ".mp4"; - } - - public FileLoadOperation(TLRPC.Audio audioLocation) { - if (audioLocation instanceof TLRPC.TL_audioEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = audioLocation.id; - location.access_hash = audioLocation.access_hash; - datacenter_id = audioLocation.dc_id; - iv = new byte[32]; - System.arraycopy(audioLocation.iv, 0, iv, 0, iv.length); - key = audioLocation.key; - } else if (audioLocation instanceof TLRPC.TL_audio) { - location = new TLRPC.TL_inputAudioFileLocation(); - datacenter_id = audioLocation.dc_id; - location.id = audioLocation.id; - location.access_hash = audioLocation.access_hash; - } - totalBytesCount = audioLocation.size; - ext = ".ogg"; - } - public FileLoadOperation(TLRPC.Document documentLocation) { - if (documentLocation instanceof TLRPC.TL_documentEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = documentLocation.id; - location.access_hash = documentLocation.access_hash; - datacenter_id = documentLocation.dc_id; - iv = new byte[32]; - System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length); - key = documentLocation.key; - } else if (documentLocation instanceof TLRPC.TL_document) { - location = new TLRPC.TL_inputDocumentFileLocation(); - location.id = documentLocation.id; - location.access_hash = documentLocation.access_hash; - datacenter_id = documentLocation.dc_id; - } - if (totalBytesCount <= 0) { - totalBytesCount = documentLocation.size; - } - if (ext == null) { + try { + if (documentLocation instanceof TLRPC.TL_documentEncrypted) { + location = new TLRPC.TL_inputEncryptedFileLocation(); + location.id = documentLocation.id; + location.access_hash = documentLocation.access_hash; + datacenter_id = documentLocation.dc_id; + iv = new byte[32]; + System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length); + key = documentLocation.key; + } else if (documentLocation instanceof TLRPC.TL_document) { + location = new TLRPC.TL_inputDocumentFileLocation(); + location.id = documentLocation.id; + location.access_hash = documentLocation.access_hash; + datacenter_id = documentLocation.dc_id; + } + if (totalBytesCount <= 0) { + totalBytesCount = documentLocation.size; + } ext = FileLoader.getDocumentFileName(documentLocation); int idx; if (ext == null || (idx = ext.lastIndexOf(".")) == -1) { ext = ""; } else { ext = ext.substring(idx); - if (ext.length() <= 1) { + } + if (ext.length() <= 1) { + if (documentLocation.mime_type != null) { + switch (documentLocation.mime_type) { + case "video/mp4": + ext = ".mp4"; + break; + case "audio/ogg": + ext = ".ogg"; + break; + default: + ext = ""; + break; + } + } else { ext = ""; } } + } catch (Exception e) { + FileLog.e("tmessages", e); + state = stateFailed; + cleanup(); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + delegate.didFailedLoadingFile(FileLoadOperation.this, 0); + } + }); } } @@ -187,6 +173,7 @@ public class FileLoadOperation { delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1); state = stateDownloading; if (location == null) { + cleanup(); Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -315,7 +302,8 @@ public class FileLoadOperation { state = stateFailed; cleanup(); if (requestInfos != null) { - for (RequestInfo requestInfo : requestInfos) { + for (int a = 0; a < requestInfos.size(); a++) { + RequestInfo requestInfo = requestInfos.get(a); if (requestInfo.requestToken != 0) { ConnectionsManager.getInstance().cancelRequest(requestInfo.requestToken, true); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 836cb9e96..6e8d4f3fe 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -272,50 +272,37 @@ public class FileLoader { }); } - public void cancelLoadFile(TLRPC.Video video) { - cancelLoadFile(video, null, null, null, null); - } - public void cancelLoadFile(TLRPC.Document document) { - cancelLoadFile(null, document, null, null, null); - } - - public void cancelLoadFile(TLRPC.Audio audio) { - cancelLoadFile(null, null, audio, null, null); + cancelLoadFile(document, null, null); } public void cancelLoadFile(TLRPC.PhotoSize photo) { - cancelLoadFile(null, null, null, photo.location, null); + cancelLoadFile(null, photo.location, null); } public void cancelLoadFile(TLRPC.FileLocation location, String ext) { - cancelLoadFile(null, null, null, location, ext); + cancelLoadFile(null, location, ext); } - private void cancelLoadFile(final TLRPC.Video video, final TLRPC.Document document, final TLRPC.Audio audio, final TLRPC.FileLocation location, final String locationExt) { - if (video == null && location == null && document == null && audio == null) { + private void cancelLoadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt) { + if (location == null && document == null) { return; } fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { String fileName = null; - if (video != null) { - fileName = getAttachFileName(video); - } else if (location != null) { + if (location != null) { fileName = getAttachFileName(location, locationExt); } else if (document != null) { fileName = getAttachFileName(document); - } else if (audio != null) { - fileName = getAttachFileName(audio); } if (fileName == null) { return; } - FileLoadOperation operation = loadOperationPaths.get(fileName); + FileLoadOperation operation = loadOperationPaths.remove(fileName); if (operation != null) { - loadOperationPaths.remove(fileName); - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { audioLoadOperationQueue.remove(operation); } else if (location != null) { photoLoadOperationQueue.remove(operation); @@ -346,39 +333,27 @@ public class FileLoader { return result[0]; } - public void loadFile(TLRPC.Video video, boolean force) { - loadFile(video, null, null, null, null, 0, force, video != null && video.key != null); - } - public void loadFile(TLRPC.PhotoSize photo, String ext, boolean cacheOnly) { - loadFile(null, null, null, photo.location, ext, photo.size, false, cacheOnly || (photo != null && photo.size == 0 || photo.location.key != null)); + loadFile(null, photo.location, ext, photo.size, false, cacheOnly || (photo != null && photo.size == 0 || photo.location.key != null)); } public void loadFile(TLRPC.Document document, boolean force, boolean cacheOnly) { - loadFile(null, document, null, null, null, 0, force, cacheOnly || document != null && document.key != null); - } - - public void loadFile(TLRPC.Audio audio, boolean force) { - loadFile(null, null, audio, null, null, 0, false, audio != null && audio.key != null); + loadFile(document, null, null, 0, force, cacheOnly || document != null && document.key != null); } public void loadFile(TLRPC.FileLocation location, String ext, int size, boolean cacheOnly) { - loadFile(null, null, null, location, ext, size, true, cacheOnly || size == 0 || (location != null && location.key != null)); + loadFile(null, location, ext, size, true, cacheOnly || size == 0 || (location != null && location.key != null)); } - private void loadFile(final TLRPC.Video video, final TLRPC.Document document, final TLRPC.Audio audio, final TLRPC.FileLocation location, final String locationExt, final int locationSize, final boolean force, final boolean cacheOnly) { + private void loadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt, final int locationSize, final boolean force, final boolean cacheOnly) { fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { String fileName = null; - if (video != null) { - fileName = getAttachFileName(video); - } else if (location != null) { + if (location != null) { fileName = getAttachFileName(location, locationExt); } else if (document != null) { fileName = getAttachFileName(document); - } else if (audio != null) { - fileName = getAttachFileName(audio); } if (fileName == null || fileName.contains("" + Integer.MIN_VALUE)) { return; @@ -389,7 +364,7 @@ public class FileLoader { if (operation != null) { if (force) { LinkedList downloadQueue; - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { downloadQueue = audioLoadOperationQueue; } else if (location != null) { downloadQueue = photoLoadOperationQueue; @@ -412,18 +387,18 @@ public class FileLoader { File storeDir = tempDir; int type = MEDIA_DIR_CACHE; - if (video != null) { - operation = new FileLoadOperation(video); - type = MEDIA_DIR_VIDEO; - } else if (location != null) { + if (location != null) { operation = new FileLoadOperation(location, locationExt, locationSize); type = MEDIA_DIR_IMAGE; } else if (document != null) { operation = new FileLoadOperation(document); - type = MEDIA_DIR_DOCUMENT; - } else if (audio != null) { - operation = new FileLoadOperation(audio); - type = MEDIA_DIR_AUDIO; + if (MessageObject.isVoiceDocument(document)) { + type = MEDIA_DIR_AUDIO; + } else if (MessageObject.isVideoDocument(document)) { + type = MEDIA_DIR_VIDEO; + } else { + type = MEDIA_DIR_DOCUMENT; + } } if (!cacheOnly) { storeDir = getDirectory(type); @@ -439,12 +414,12 @@ public class FileLoader { if (delegate != null) { delegate.fileDidLoaded(finalFileName, finalFile, finalType); } - checkDownloadQueue(audio, location, finalFileName); + checkDownloadQueue(document, location, finalFileName); } @Override public void didFailedLoadingFile(FileLoadOperation operation, int canceled) { - checkDownloadQueue(audio, location, finalFileName); + checkDownloadQueue(document, location, finalFileName); if (delegate != null) { delegate.fileDidFailedLoad(finalFileName, canceled); } @@ -458,7 +433,7 @@ public class FileLoader { } }); int maxCount = force ? 3 : 1; - if (audio != null) { + if (type == MEDIA_DIR_AUDIO) { if (currentAudioLoadOperationsCount < maxCount) { currentAudioLoadOperationsCount++; operation.start(); @@ -496,13 +471,13 @@ public class FileLoader { }); } - private void checkDownloadQueue(final TLRPC.Audio audio, final TLRPC.FileLocation location, final String arg1) { + private void checkDownloadQueue(final TLRPC.Document document, final TLRPC.FileLocation location, final String arg1) { fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { loadOperationPaths.remove(arg1); FileLoadOperation operation; - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { currentAudioLoadOperationsCount--; if (!audioLoadOperationQueue.isEmpty()) { operation = audioLoadOperationQueue.get(0); @@ -550,6 +525,44 @@ public class FileLoader { this.delegate = delegate; } + public static String getMessageFileName(TLRPC.Message message) { + if (message == null) { + return ""; + } + if (message instanceof TLRPC.TL_messageService) { + if (message.action.photo != null) { + ArrayList sizes = message.action.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } + } else { + if (message.media instanceof TLRPC.TL_messageMediaDocument) { + return getAttachFileName(message.media.document); + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + ArrayList sizes = message.media.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) { + ArrayList sizes = message.media.webpage.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } + } + return ""; + } + public static File getPathToMessage(TLRPC.Message message) { if (message == null) { return new File(""); @@ -565,12 +578,8 @@ public class FileLoader { } } } else { - if (message.media instanceof TLRPC.TL_messageMediaVideo) { - return getPathToAttach(message.media.video); - } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + if (message.media instanceof TLRPC.TL_messageMediaDocument) { return getPathToAttach(message.media.document); - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - return getPathToAttach(message.media.audio); } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { ArrayList sizes = message.media.photo.sizes; if (sizes.size() > 0) { @@ -605,19 +614,18 @@ public class FileLoader { if (forceCache) { dir = getInstance().getDirectory(MEDIA_DIR_CACHE); } else { - if (attach instanceof TLRPC.Video) { - TLRPC.Video video = (TLRPC.Video) attach; - if (video.key != null) { - dir = getInstance().getDirectory(MEDIA_DIR_CACHE); - } else { - dir = getInstance().getDirectory(MEDIA_DIR_VIDEO); - } - } else if (attach instanceof TLRPC.Document) { + if (attach instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) attach; if (document.key != null) { dir = getInstance().getDirectory(MEDIA_DIR_CACHE); } else { - dir = getInstance().getDirectory(MEDIA_DIR_DOCUMENT); + if (MessageObject.isVoiceDocument(document)) { + dir = getInstance().getDirectory(MEDIA_DIR_AUDIO); + } else if (MessageObject.isVideoDocument(document)) { + dir = getInstance().getDirectory(MEDIA_DIR_VIDEO); + } else { + dir = getInstance().getDirectory(MEDIA_DIR_DOCUMENT); + } } } else if (attach instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize photoSize = (TLRPC.PhotoSize) attach; @@ -626,13 +634,6 @@ public class FileLoader { } else { dir = getInstance().getDirectory(MEDIA_DIR_IMAGE); } - } else if (attach instanceof TLRPC.Audio) { - TLRPC.Audio audio = (TLRPC.Audio) attach; - if (audio.key != null) { - dir = getInstance().getDirectory(MEDIA_DIR_CACHE); - } else { - dir = getInstance().getDirectory(MEDIA_DIR_AUDIO); - } } else if (attach instanceof TLRPC.FileLocation) { TLRPC.FileLocation fileLocation = (TLRPC.FileLocation) attach; if (fileLocation.key != null || fileLocation.volume_id == Integer.MIN_VALUE && fileLocation.local_id < 0) { @@ -708,10 +709,7 @@ public class FileLoader { } public static String getAttachFileName(TLObject attach, String ext) { - if (attach instanceof TLRPC.Video) { - TLRPC.Video video = (TLRPC.Video) attach; - return video.dc_id + "_" + video.id + "." + (ext != null ? ext : "mp4"); - } else if (attach instanceof TLRPC.Document) { + if (attach instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) attach; String docExt = null; if (docExt == null) { @@ -723,6 +721,23 @@ public class FileLoader { docExt = docExt.substring(idx); } } + if (docExt.length() <= 1) { + if (document.mime_type != null) { + switch (document.mime_type) { + case "video/mp4": + docExt = ".mp4"; + break; + case "audio/ogg": + docExt = ".ogg"; + break; + default: + docExt = ""; + break; + } + } else { + docExt = ""; + } + } if (docExt.length() > 1) { return document.dc_id + "_" + document.id + docExt; } else { @@ -734,9 +749,6 @@ public class FileLoader { return ""; } return photo.location.volume_id + "_" + photo.location.local_id + "." + (ext != null ? ext : "jpg"); - } else if (attach instanceof TLRPC.Audio) { - TLRPC.Audio audio = (TLRPC.Audio) attach; - return audio.dc_id + "_" + audio.id + "." + (ext != null ? ext : "ogg"); } else if (attach instanceof TLRPC.FileLocation) { if (attach instanceof TLRPC.TL_fileLocationUnavailable) { return ""; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 285fdb68c..68efb2c5f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -1001,8 +1001,8 @@ public class ImageLoader { } } if (imageReceiverArray.size() == 0) { - for (ImageReceiver receiver : imageReceiverArray) { - imageLoadingByTag.remove(receiver.getTag(thumb)); + for (int a = 0; a < imageReceiverArray.size(); a++) { + imageLoadingByTag.remove(imageReceiverArray.get(a).getTag(thumb)); } imageReceiverArray.clear(); if (location != null) { @@ -1233,18 +1233,7 @@ public class ImageLoader { FileLog.e("tmessages", "file system changed"); Runnable r = new Runnable() { public void run() { - cacheOutQueue.postRunnable(new Runnable() { - @Override - public void run() { - final HashMap paths = createMediaPaths(); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - FileLoader.getInstance().setMediaDirs(paths); - } - }); - } - }); + checkMediaPaths(); } }; if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { @@ -1285,6 +1274,10 @@ public class ImageLoader { mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath); FileLoader.getInstance().setMediaDirs(mediaDirs); + checkMediaPaths(); + } + + public void checkMediaPaths() { cacheOutQueue.postRunnable(new Runnable() { @Override public void run() { @@ -1702,7 +1695,7 @@ public class ImageLoader { if (thumb != 2) { CacheImage img = new CacheImage(); - if (httpLocation != null && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) || imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) { + if (httpLocation != null && !httpLocation.startsWith("vthumb") && !httpLocation.startsWith("thumb") && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) || imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) { img.animatedFile = true; } @@ -1801,7 +1794,7 @@ public class ImageLoader { } if (httpLocation != null) { key = Utilities.MD5(httpLocation); - url = key + "." + getHttpUrlExtension(httpLocation); + url = key + "." + getHttpUrlExtension(httpLocation, "jpg"); } else if (imageLocation != null) { if (imageLocation instanceof TLRPC.FileLocation) { TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation; @@ -1822,7 +1815,11 @@ public class ImageLoader { docExt = ""; } else { docExt = docExt.substring(idx); - if (docExt.length() <= 1) { + } + if (docExt.length() <= 1) { + if (document.mime_type != null && document.mime_type.equals("video/mp4")) { + docExt = ".mp4"; + } else { docExt = ""; } } @@ -1965,7 +1962,7 @@ public class ImageLoader { ext = "jpg"; } } - File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + ext); + File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + getHttpUrlExtension(url, extension)); file.delete(); HttpFileTask task = new HttpFileTask(url, file, ext); @@ -2279,14 +2276,14 @@ public class ImageLoader { } } - public static String getHttpUrlExtension(String url) { + public static String getHttpUrlExtension(String url, String defaultExt) { String ext = null; int idx = url.lastIndexOf("."); if (idx != -1) { ext = url.substring(idx + 1); } if (ext == null || ext.length() == 0 || ext.length() > 4) { - ext = "jpg"; + ext = defaultExt; } return ext; } @@ -2300,10 +2297,6 @@ public class ImageLoader { break; } } - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { - if (message.media.video.thumb instanceof TLRPC.TL_photoCachedSize) { - photoSize = message.media.video.thumb; - } } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { if (message.media.document.thumb instanceof TLRPC.TL_photoCachedSize) { photoSize = message.media.document.thumb; @@ -2350,8 +2343,6 @@ public class ImageLoader { break; } } - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { - message.media.video.thumb = newPhotoSize; } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { message.media.document.thumb = newPhotoSize; } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { @@ -2369,7 +2360,8 @@ public class ImageLoader { if (messages == null || messages.isEmpty()) { return; } - for (TLRPC.Message message : messages) { + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); saveMessageThumbs(message); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index 456b7cc42..340d5f120 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -138,7 +138,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg if ((fileLocation == null && httpUrl == null && thumbLocation == null) || (fileLocation != null && !(fileLocation instanceof TLRPC.TL_fileLocation) && !(fileLocation instanceof TLRPC.TL_fileEncryptedLocation) - && !(fileLocation instanceof TLRPC.TL_document))) { + && !(fileLocation instanceof TLRPC.TL_document) + && !(fileLocation instanceof TLRPC.TL_documentEncrypted))) { recycleBitmap(null, false); recycleBitmap(null, true); currentKey = null; @@ -260,6 +261,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } public void setOrientation(int angle, boolean center) { + while (angle < 0) { + angle += 360; + } + while (angle > 360) { + angle -= 360; + } orientation = angle; centerRotation = center; } @@ -376,7 +383,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } else { int bitmapW; int bitmapH; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { bitmapW = bitmapDrawable.getIntrinsicHeight(); bitmapH = bitmapDrawable.getIntrinsicWidth(); } else { @@ -413,7 +420,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg canvas.save(); canvas.clipRect(imageX, imageY, imageX + imageW, imageY + imageH); - if (orientation != 0) { + if (orientation % 360 != 0) { if (centerRotation) { canvas.rotate(orientation, imageW / 2, imageH / 2); } else { @@ -428,7 +435,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg bitmapH /= scaleW; drawRegion.set(imageX, imageY - (bitmapH - imageH) / 2, imageX + imageW, imageY + (bitmapH + imageH) / 2); } - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { int width = (drawRegion.right - drawRegion.left) / 2; int height = (drawRegion.bottom - drawRegion.top) / 2; int centerX = (drawRegion.right + drawRegion.left) / 2; @@ -457,7 +464,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg canvas.restore(); } else { canvas.save(); - if (orientation != 0) { + if (orientation % 360 != 0) { if (centerRotation) { canvas.rotate(orientation, imageW / 2, imageH / 2); } else { @@ -465,7 +472,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } } drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { int width = (drawRegion.right - drawRegion.left) / 2; int height = (drawRegion.bottom - drawRegion.top) / 2; int centerX = (drawRegion.right + drawRegion.left) / 2; @@ -597,18 +604,18 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg public int getBitmapWidth() { if (currentImage instanceof AnimatedFileDrawable) { - return orientation == 0 || orientation == 180 ? currentImage.getIntrinsicWidth() : currentImage.getIntrinsicHeight(); + return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicWidth() : currentImage.getIntrinsicHeight(); } Bitmap bitmap = getBitmap(); - return orientation == 0 || orientation == 180 ? bitmap.getWidth() : bitmap.getHeight(); + return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getWidth() : bitmap.getHeight(); } public int getBitmapHeight() { if (currentImage instanceof AnimatedFileDrawable) { - return orientation == 0 || orientation == 180 ? currentImage.getIntrinsicHeight() : currentImage.getIntrinsicWidth(); + return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicHeight() : currentImage.getIntrinsicWidth(); } Bitmap bitmap = getBitmap(); - return orientation == 0 || orientation == 180 ? bitmap.getHeight() : bitmap.getWidth(); + return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getHeight() : bitmap.getWidth(); } public void setVisible(boolean value, boolean invalidate) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index db7b99f7f..97ea54fdf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -700,6 +700,30 @@ public class LocaleController { return "LOC_ERR"; } + public static String formatDateAudio(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + rightNow.setTimeInMillis(date * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (dateDay == day && year == dateYear) { + return String.format("%s %s", LocaleController.getString("TodayAt", R.string.TodayAt), getInstance().formatterDay.format(new Date(date * 1000))); + } else if (dateDay + 1 == day && year == dateYear) { + return String.format("%s %s", LocaleController.getString("YesterdayAt", R.string.YesterdayAt), getInstance().formatterDay.format(new Date(date * 1000))); + } else if (year == dateYear) { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterMonth.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + } else { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR"; + } + public static String formatDateOnline(long date) { try { Calendar rightNow = Calendar.getInstance(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 902630b06..5d5cb3297 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -46,6 +46,8 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Vibrator; import android.provider.MediaStore; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; import org.telegram.messenger.audioinfo.AudioInfo; import org.telegram.messenger.query.SharedMediaQuery; @@ -55,6 +57,8 @@ import org.telegram.messenger.video.Mp4Movie; import org.telegram.messenger.video.OutputSurface; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.PhotoViewer; import java.io.File; import java.io.FileInputStream; @@ -70,37 +74,27 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; -public class MediaController implements NotificationCenter.NotificationCenterDelegate, SensorEventListener { +public class MediaController implements AudioManager.OnAudioFocusChangeListener, NotificationCenter.NotificationCenterDelegate, SensorEventListener { private native int startRecord(String path); - private native int writeFrame(ByteBuffer frame, int len); - private native void stopRecord(); - private native int openOpusFile(String path); - private native int seekOpusFile(float position); - private native int isOpusFile(String path); - private native void closeOpusFile(); - private native void readOpusFile(ByteBuffer buffer, int capacity, int[] args); - private native long getTotalPcmDuration(); + public native byte[] getWaveform(String path); + public native byte[] getWaveform2(short[] array, int length); public static int[] readArgs = new int[3]; public interface FileDownloadProgressListener { void onFailedDownload(String fileName); - void onSuccessDownload(String fileName); - void onProgressDownload(String fileName, float progress); - void onProgressUpload(String fileName, float progress, boolean isEncrypted); - int getObserverTag(); } @@ -214,14 +208,45 @@ public class MediaController implements NotificationCenter.NotificationCenterDel private HashMap typingTimes = new HashMap<>(); private SensorManager sensorManager; - private Sensor proximitySensor; private boolean ignoreProximity; private PowerManager.WakeLock proximityWakeLock; + private Sensor proximitySensor; + private Sensor accelerometerSensor; + private Sensor linearSensor; + private Sensor gravitySensor; + private boolean raiseToEarRecord; + private ChatActivity raiseChat; + private boolean accelerometerVertical; + private int raisedToTop; + private int raisedToBack; + private int countLess; + private long timeSinceRaise; + private long lastTimestamp = 0; + private boolean proximityTouched; + private boolean proximityHasDifferentValues; + private float lastProximityValue = -100; + private boolean useFrontSpeaker; + private boolean inputFieldHasText; + private boolean allowStartRecord; + private boolean ignoreOnPause; + private boolean sensorsStarted; + private float previousAccValue; + private float[] gravity = new float[3]; + private float[] gravityFast = new float[3]; + private float[] linearAcceleration = new float[3]; + + private boolean hasAudioFoces; + private boolean callInProgress; private ArrayList videoConvertQueue = new ArrayList<>(); private final Object videoQueueSync = new Object(); private boolean cancelCurrentVideoConversion = false; private boolean videoConvertFirstWrite = true; + private HashMap generatingWaveform = new HashMap<>(); + + private boolean voiceMessagesPlaylistUnread; + private ArrayList voiceMessagesPlaylist; + private HashMap voiceMessagesPlaylistMap; public static final int AUTODOWNLOAD_MASK_PHOTO = 1; public static final int AUTODOWNLOAD_MASK_AUDIO = 2; @@ -243,6 +268,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel private boolean saveToGallery = true; private boolean autoplayGifs = true; + private boolean raiseToSpeak = true; private boolean shuffleMusic; private int repeatMode; @@ -268,7 +294,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel private int ignoreFirstProgress = 0; private Timer progressTimer = null; private final Object progressTimerSync = new Object(); - private boolean useFrontSpeaker; private int buffersWrited; private ArrayList playlist = new ArrayList<>(); private ArrayList shuffledPlaylist = new ArrayList<>(); @@ -278,7 +303,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel private AudioInfo audioInfo; private AudioRecord audioRecorder = null; - private TLRPC.TL_audio recordingAudio = null; + private TLRPC.TL_document recordingAudio = null; private File recordingAudioFile = null; private long recordStartTime; private long recordTimeCount; @@ -291,13 +316,15 @@ public class MediaController implements NotificationCenter.NotificationCenterDel private ArrayList freePlayerBuffers = new ArrayList<>(); private final Object playerSync = new Object(); private final Object playerObjectSync = new Object(); + private short[] recordSamples = new short[1024]; + private long samplesCount; private final Object sync = new Object(); private ArrayList recordBuffers = new ArrayList<>(); private ByteBuffer fileBuffer; private int recordBufferSize; - private boolean sendAfterDone; + private int sendAfterDone; private Runnable recordStartRunnable; private DispatchQueue recordQueue; @@ -317,18 +344,39 @@ public class MediaController implements NotificationCenter.NotificationCenterDel buffer.rewind(); int len = audioRecorder.read(buffer, buffer.capacity()); if (len > 0) { + buffer.limit(len); double sum = 0; try { + long newSamplesCount = samplesCount + len / 2; + int currentPart = (int) (((double) samplesCount / (double) newSamplesCount) * recordSamples.length); + int newPart = recordSamples.length - currentPart; + float sampleStep; + if (currentPart != 0) { + sampleStep = (float) recordSamples.length / (float) currentPart; + float currentNum = 0; + for (int a = 0; a < currentPart; a++) { + recordSamples[a] = recordSamples[(int) currentNum]; + currentNum += sampleStep; + } + } + int currentNum = currentPart; + float nextNum = 0; + sampleStep = (float) len / 2 / (float) newPart; for (int i = 0; i < len / 2; i++) { short peak = buffer.getShort(); sum += peak * peak; + if (i == (int) nextNum && currentNum < recordSamples.length) { + recordSamples[currentNum] = peak; + nextNum += sampleStep; + currentNum++; + } } + samplesCount = newSamplesCount; } catch (Exception e) { FileLog.e("tmessages", e); } buffer.position(0); final double amplitude = Math.sqrt(sum / len / 2); - buffer.limit(len); final ByteBuffer finalBuffer = buffer; final boolean flush = len != buffer.capacity(); if (len != 0) { @@ -518,6 +566,14 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } try { sensorManager = (SensorManager) ApplicationLoader.applicationContext.getSystemService(Context.SENSOR_SERVICE); + linearSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); + if (linearSensor == null || gravitySensor == null) { + FileLog.e("tmessages", "gravity or linear sensor not found"); + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + linearSensor = null; + gravitySensor = null; + } proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); PowerManager powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); proximityWakeLock = powerManager.newWakeLock(0x00000020, "proximity"); @@ -538,6 +594,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel roamingDownloadMask = preferences.getInt("roamingDownloadMask", 0); saveToGallery = preferences.getBoolean("save_gallery", false); autoplayGifs = preferences.getBoolean("autoplay_gif", true) && Build.VERSION.SDK_INT >= 11; + raiseToSpeak = preferences.getBoolean("raise_to_speak", true) && Build.VERSION.SDK_INT >= 11; shuffleMusic = preferences.getBoolean("shuffleMusic", false); repeatMode = preferences.getInt("repeatMode", 0); @@ -545,10 +602,11 @@ public class MediaController implements NotificationCenter.NotificationCenterDel @Override public void run() { NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidFailedLoad); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.didReceivedNewMessages); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.messagesDeleted); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidLoaded); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileUploadProgressChanged); - NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.messagesDeleted); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.removeAllMessagesFromDialog); NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.musicDidLoaded); } @@ -597,9 +655,47 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } catch (Exception e) { FileLog.e("tmessages", e); } + + try { + PhoneStateListener phoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (state == TelephonyManager.CALL_STATE_RINGING) { + if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } else if (recordStartRunnable != null || recordingAudio != null) { + stopRecording(2); + } + callInProgress = true; + } else if (state == TelephonyManager.CALL_STATE_IDLE) { + callInProgress = false; + } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) { + callInProgress = true; + } + } + }; + TelephonyManager mgr = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + if (mgr != null) { + mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } } - private void startProgressTimer() { + @Override + public void onAudioFocusChange(int focusChange) { + if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { + if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } + hasAudioFoces = false; + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { + //MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } + } + + private void startProgressTimer(final MessageObject currentPlayingMessageObject) { synchronized (progressTimerSync) { if (progressTimer != null) { try { @@ -617,7 +713,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { - if (playingMessageObject != null && (audioPlayer != null || audioTrackPlayer != null) && !isPaused) { + if (currentPlayingMessageObject != null && (audioPlayer != null || audioTrackPlayer != null) && !isPaused) { try { if (ignoreFirstProgress != 0) { ignoreFirstProgress--; @@ -639,9 +735,9 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } lastProgress = progress; - playingMessageObject.audioProgress = value; - playingMessageObject.audioProgressSec = lastProgress / 1000; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), value); + currentPlayingMessageObject.audioProgress = value; + currentPlayingMessageObject.audioProgressSec = lastProgress / 1000; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, currentPlayingMessageObject.getId(), value); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -681,7 +777,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel videoConvertQueue.clear(); playlist.clear(); shuffledPlaylist.clear(); + generatingWaveform.clear(); typingTimes.clear(); + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; cancelVideoConvert(null); } @@ -732,7 +831,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } else { for (int a = 0; a < audioDownloadQueue.size(); a++) { DownloadObject downloadObject = audioDownloadQueue.get(a); - FileLoader.getInstance().cancelLoadFile((TLRPC.Audio) downloadObject.object); + FileLoader.getInstance().cancelLoadFile((TLRPC.Document) downloadObject.object); } audioDownloadQueue.clear(); } @@ -755,7 +854,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } else { for (int a = 0; a < videoDownloadQueue.size(); a++) { DownloadObject downloadObject = videoDownloadQueue.get(a); - FileLoader.getInstance().cancelLoadFile((TLRPC.Video) downloadObject.object); + FileLoader.getInstance().cancelLoadFile((TLRPC.Document) downloadObject.object); } videoDownloadQueue.clear(); } @@ -855,12 +954,8 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } boolean added = true; - if (downloadObject.object instanceof TLRPC.Audio) { - FileLoader.getInstance().loadFile((TLRPC.Audio) downloadObject.object, false); - } else if (downloadObject.object instanceof TLRPC.PhotoSize) { + if (downloadObject.object instanceof TLRPC.PhotoSize) { FileLoader.getInstance().loadFile((TLRPC.PhotoSize) downloadObject.object, null, false); - } else if (downloadObject.object instanceof TLRPC.Video) { - FileLoader.getInstance().loadFile((TLRPC.Video) downloadObject.object, false); } else if (downloadObject.object instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) downloadObject.object; FileLoader.getInstance().loadFile(document, false, false); @@ -1192,7 +1287,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel long dialog_id = delayedMessage.obj.getDialogId(); Long lastTime = typingTimes.get(dialog_id); if (lastTime == null || lastTime + 4000 < System.currentTimeMillis()) { - if (delayedMessage.videoLocation != null) { + if (MessageObject.isVideoDocument(delayedMessage.documentLocation)) { MessagesController.getInstance().sendTyping(dialog_id, 5, 0); } else if (delayedMessage.documentLocation != null) { MessagesController.getInstance().sendTyping(dialog_id, 3, 0); @@ -1208,14 +1303,24 @@ public class MediaController implements NotificationCenter.NotificationCenterDel FileLog.e("tmessages", e); } } else if (id == NotificationCenter.messagesDeleted) { + int channelId = (Integer) args[1]; + ArrayList markAsDeletedMessages = (ArrayList) args[0]; if (playingMessageObject != null) { - int channelId = (Integer) args[1]; - if (channelId != playingMessageObject.messageOwner.to_id.channel_id) { - return; + if (channelId == playingMessageObject.messageOwner.to_id.channel_id) { + if (markAsDeletedMessages.contains(playingMessageObject.getId())) { + cleanupPlayer(true, true); + } } - ArrayList markAsDeletedMessages = (ArrayList) args[0]; - if (markAsDeletedMessages.contains(playingMessageObject.getId())) { - cleanupPlayer(false, true); + } + if (voiceMessagesPlaylist != null && !voiceMessagesPlaylist.isEmpty()) { + MessageObject messageObject = voiceMessagesPlaylist.get(0); + if (channelId == messageObject.messageOwner.to_id.channel_id) { + for (int a = 0; a < markAsDeletedMessages.size(); a++) { + messageObject = voiceMessagesPlaylistMap.remove(markAsDeletedMessages.get(a)); + if (messageObject != null) { + voiceMessagesPlaylist.remove(messageObject); + } + } } } } else if (id == NotificationCenter.removeAllMessagesFromDialog) { @@ -1235,6 +1340,21 @@ public class MediaController implements NotificationCenter.NotificationCenterDel currentPlaylistNum += arrayList.size(); } } + } else if (id == NotificationCenter.didReceivedNewMessages) { + if (voiceMessagesPlaylist != null && !voiceMessagesPlaylist.isEmpty()) { + MessageObject messageObject = voiceMessagesPlaylist.get(0); + long did = (Long) args[0]; + if (did == messageObject.getDialogId()) { + ArrayList arr = (ArrayList) args[1]; + for (int a = 0; a < arr.size(); a++) { + messageObject = arr.get(a); + if (messageObject.isVoice() && (!voiceMessagesPlaylistUnread || messageObject.isContentUnread() && !messageObject.isOut())) { + voiceMessagesPlaylist.add(messageObject); + voiceMessagesPlaylistMap.put(messageObject.getId(), messageObject); + } + } + } + } } } @@ -1329,7 +1449,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel audioTrackPlayer.setNotificationMarkerPosition(1); } if (finalBuffersWrited == 1) { - cleanupPlayer(true, true); + cleanupPlayer(true, true, true); } } } @@ -1353,33 +1473,195 @@ public class MediaController implements NotificationCenter.NotificationCenterDel }); } + protected boolean isRecordingAudio() { + return recordStartRunnable != null || recordingAudio != null; + } + private boolean isNearToSensor(float value) { return value < 5.0f && value != proximitySensor.getMaximumRange(); } @Override public void onSensorChanged(SensorEvent event) { - FileLog.e("tmessages", "proximity changed to " + event.values[0]); - if (proximitySensor != null && audioTrackPlayer == null && audioPlayer == null || isPaused || (useFrontSpeaker == isNearToSensor(event.values[0]))) { + if (!sensorsStarted) { return; } - boolean newValue = isNearToSensor(event.values[0]); - try { - if (newValue && NotificationsController.getInstance().audioManager.isWiredHeadsetOn()) { - return; + if (event.sensor == proximitySensor) { + FileLog.e("tmessages", "proximity changed to " + event.values[0]); + if (lastProximityValue == -100) { + lastProximityValue = event.values[0]; + } else if (lastProximityValue != event.values[0]) { + proximityHasDifferentValues = true; } - } catch (Exception e) { - FileLog.e("tmessages", e); + if (proximityHasDifferentValues) { + proximityTouched = isNearToSensor(event.values[0]); + } + } else if (event.sensor == accelerometerSensor) { + //0.98039215f + final double alpha = lastTimestamp == 0 ? 0.98f : 1.0 / (1.0 + (event.timestamp - lastTimestamp) / 1000000000.0); + final float alphaFast = 0.8f; + lastTimestamp = event.timestamp; + gravity[0] = (float) (alpha * gravity[0] + (1.0 - alpha) * event.values[0]); + gravity[1] = (float) (alpha * gravity[1] + (1.0 - alpha) * event.values[1]); + gravity[2] = (float) (alpha * gravity[2] + (1.0 - alpha) * event.values[2]); + gravityFast[0] = (alphaFast * gravity[0] + (1.0f - alphaFast) * event.values[0]); + gravityFast[1] = (alphaFast * gravity[1] + (1.0f - alphaFast) * event.values[1]); + gravityFast[2] = (alphaFast * gravity[2] + (1.0f - alphaFast) * event.values[2]); + + linearAcceleration[0] = event.values[0] - gravity[0]; + linearAcceleration[1] = event.values[1] - gravity[1]; + linearAcceleration[2] = event.values[2] - gravity[2]; + } else if (event.sensor == linearSensor) { + linearAcceleration[0] = event.values[0]; + linearAcceleration[1] = event.values[1]; + linearAcceleration[2] = event.values[2]; + } else if (event.sensor == gravitySensor) { + gravityFast[0] = gravity[0] = event.values[0]; + gravityFast[1] = gravity[1] = event.values[1]; + gravityFast[2] = gravity[2] = event.values[2]; + } + final float minDist = 15.0f; + final int minCount = 6; + final int countLessMax = 10; + if (event.sensor == linearSensor || event.sensor == gravitySensor || event.sensor == accelerometerSensor) { + float val = gravity[0] * linearAcceleration[0] + gravity[1] * linearAcceleration[1] + gravity[2] * linearAcceleration[2]; + if (raisedToBack != minCount) { + if (val > 0 && previousAccValue > 0) { + if (val > minDist && raisedToBack == 0) { + if (raisedToTop < minCount && !proximityTouched) { + raisedToTop++; + if (raisedToTop == minCount) { + countLess = 0; + } + } + } else { + if (val < minDist) { + countLess++; + } + if (countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + } + } + } else if (val < 0 && previousAccValue < 0) { + if (raisedToTop == minCount && val < -minDist) { + if (raisedToBack < minCount) { + raisedToBack++; + if (raisedToBack == minCount) { + raisedToTop = 0; + countLess = 0; + timeSinceRaise = System.currentTimeMillis(); + //FileLog.e("tmessages", "motion detected"); + } + } + } else { + if (val > -minDist) { + countLess++; + } + if (countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToTop = 0; + raisedToBack = 0; + countLess = 0; + } + } + } + } + previousAccValue = val; + accelerometerVertical = gravityFast[1] > 2.5f && Math.abs(gravityFast[2]) < 4.0f && /*Math.abs(gravityFast[0]) < 9.0f &&*/ Math.abs(gravityFast[0]) > 1.5f; + //FileLog.e("tmessages", accelerometerVertical + " val = " + val + " acc (" + linearAcceleration[0] + ", " + linearAcceleration[1] + ", " + linearAcceleration[2] + ") grav (" + gravityFast[0] + ", " + gravityFast[1] + ", " + gravityFast[2] + ")"); + } + if (raisedToBack == minCount && accelerometerVertical && proximityTouched && !NotificationsController.getInstance().audioManager.isWiredHeadsetOn()) { + FileLog.e("tmessages", "sensor values reached"); + if (playingMessageObject == null && recordStartRunnable == null && recordingAudio == null && !PhotoViewer.getInstance().isVisible() && ApplicationLoader.isScreenOn && !inputFieldHasText && allowStartRecord && raiseChat != null && !callInProgress) { + if (!raiseToEarRecord) { + FileLog.e("tmessages", "start record"); + useFrontSpeaker = true; + if (!raiseChat.playFirstUnreadVoiceMessage()) { + raiseToEarRecord = true; + useFrontSpeaker = false; + startRecording(raiseChat.getDialogId(), null, false); + } + ignoreOnPause = true; + if (proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + } + } else if (playingMessageObject != null && playingMessageObject.isVoice()) { + if (!useFrontSpeaker) { + FileLog.e("tmessages", "start listen"); + if (proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + useFrontSpeaker = true; + startAudioAgain(false); + ignoreOnPause = true; + } + } + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + } else if (proximityTouched) { + if (playingMessageObject != null && playingMessageObject.isVoice()) { + if (!useFrontSpeaker) { + FileLog.e("tmessages", "start listen by proximity only"); + if (proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + useFrontSpeaker = true; + startAudioAgain(false); + ignoreOnPause = true; + } + } + } else if (!proximityTouched) { + if (raiseToEarRecord) { + FileLog.e("tmessages", "stop record"); + stopRecording(2); + raiseToEarRecord = false; + ignoreOnPause = false; + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + } else if (useFrontSpeaker) { + FileLog.e("tmessages", "stop listen"); + useFrontSpeaker = false; + startAudioAgain(true); + ignoreOnPause = false; + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + } + } + if (timeSinceRaise != 0 && raisedToBack == minCount && Math.abs(System.currentTimeMillis() - timeSinceRaise) > 1000) { + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + timeSinceRaise = 0; + } + } + + public void startRecordingIfFromSpeaker() { + if (!useFrontSpeaker || raiseChat == null || !allowStartRecord) { + return; + } + raiseToEarRecord = true; + startRecording(raiseChat.getDialogId(), null, false); + ignoreOnPause = true; + } + + private void startAudioAgain(boolean paused) { + if (playingMessageObject == null) { + return; } - ignoreProximity = true; - useFrontSpeaker = newValue; NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker); MessageObject currentMessageObject = playingMessageObject; float progress = playingMessageObject.audioProgress; cleanupPlayer(false, true); currentMessageObject.audioProgress = progress; playAudio(currentMessageObject); - ignoreProximity = false; + if (paused) { + pauseAudio(currentMessageObject); + } } @Override @@ -1387,42 +1669,90 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } - private void stopProximitySensor() { - if (ignoreProximity) { + public void setInputFieldHasText(boolean value) { + inputFieldHasText = value; + } + + public void setAllowStartRecord(boolean value) { + allowStartRecord = value; + } + + public void startRaiseToEarSensors(ChatActivity chatActivity) { + if (chatActivity == null || accelerometerSensor == null && (gravitySensor == null || linearAcceleration == null) || proximitySensor == null) { return; } - try { - useFrontSpeaker = false; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker); - if (sensorManager != null && proximitySensor != null) { - sensorManager.unregisterListener(this); - } - if (proximityWakeLock != null && proximityWakeLock.isHeld()) { - proximityWakeLock.release(); - } - } catch (Throwable e) { - FileLog.e("tmessages", e); + raiseChat = chatActivity; + if (!raiseToSpeak && (playingMessageObject == null || !playingMessageObject.isVoice())) { + return; + } + if (!sensorsStarted) { + gravity[0] = gravity[1] = gravity[2] = 0; + linearAcceleration[0] = linearAcceleration[1] = linearAcceleration[2] = 0; + gravityFast[0] = gravityFast[1] = gravityFast[2] = 0; + lastTimestamp = 0; + previousAccValue = 0; + raisedToTop = 0; + countLess = 0; + raisedToBack = 0; + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (gravitySensor != null) { + sensorManager.registerListener(MediaController.this, gravitySensor, 30000); + } + if (linearSensor != null) { + sensorManager.registerListener(MediaController.this, linearSensor, 30000); + } + if (accelerometerSensor != null) { + sensorManager.registerListener(MediaController.this, accelerometerSensor, 30000); + } + sensorManager.registerListener(MediaController.this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); + } + }); + sensorsStarted = true; } } - private void startProximitySensor() { - if (ignoreProximity) { + public void stopRaiseToEarSensors(ChatActivity chatActivity) { + if (ignoreOnPause) { + ignoreOnPause = false; return; } - try { - if (sensorManager != null && proximitySensor != null) { - sensorManager.registerListener(this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); + if (!sensorsStarted || ignoreOnPause || accelerometerSensor == null && (gravitySensor == null || linearAcceleration == null) || proximitySensor == null || raiseChat != chatActivity) { + return; + } + raiseChat = null; + stopRecording(0); + sensorsStarted = false; + accelerometerVertical = false; + proximityTouched = false; + raiseToEarRecord = false; + useFrontSpeaker = false; + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (linearSensor != null) { + sensorManager.unregisterListener(MediaController.this, linearSensor); + } + if (gravitySensor != null) { + sensorManager.unregisterListener(MediaController.this, gravitySensor); + } + if (accelerometerSensor != null) { + sensorManager.unregisterListener(MediaController.this, accelerometerSensor); + } + sensorManager.unregisterListener(MediaController.this, proximitySensor); } - if (!NotificationsController.getInstance().audioManager.isWiredHeadsetOn() && proximityWakeLock != null && !proximityWakeLock.isHeld()) { - proximityWakeLock.acquire(); - } - } catch (Exception e) { - FileLog.e("tmessages", e); + }); + if (proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); } } public void cleanupPlayer(boolean notify, boolean stopService) { - stopProximitySensor(); + cleanupPlayer(notify, stopService, false); + } + + public void cleanupPlayer(boolean notify, boolean stopService, boolean byVoiceEnd) { if (audioPlayer != null) { try { audioPlayer.reset(); @@ -1467,20 +1797,48 @@ public class MediaController implements NotificationCenter.NotificationCenterDel MessageObject lastFile = playingMessageObject; playingMessageObject.audioProgress = 0.0f; playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); playingMessageObject = null; downloadingCurrentMessage = false; if (notify) { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidReset, lastFile.getId(), stopService); + if (voiceMessagesPlaylist != null) { + if (byVoiceEnd && voiceMessagesPlaylist.get(0) == lastFile) { + voiceMessagesPlaylist.remove(0); + voiceMessagesPlaylistMap.remove(lastFile.getId()); + if (voiceMessagesPlaylist.isEmpty()) { + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; + } + } else { + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; + } + } + boolean next = false; + if (voiceMessagesPlaylist != null) { + MessageObject nextVoiceMessage = voiceMessagesPlaylist.get(0); + playAudio(nextVoiceMessage); + } else { + if (lastFile.isVoice() && lastFile.getId() != 0) { + startRecordingIfFromSpeaker(); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidReset, lastFile.getId(), stopService); + } } if (stopService) { Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); ApplicationLoader.applicationContext.stopService(intent); } } + if (!useFrontSpeaker && !raiseToSpeak) { + ChatActivity chat = raiseChat; + stopRaiseToEarSensors(raiseChat); + raiseChat = chat; + } } private void seekOpusPlayer(final float progress) { - if (currentTotalPcmDuration * progress == currentTotalPcmDuration) { + if (progress == 1.0f) { return; } if (!isPaused) { @@ -1573,11 +1931,13 @@ public class MediaController implements NotificationCenter.NotificationCenterDel shuffledPlaylist.clear(); return false; } - if (shuffleMusic) { - buildShuffledPlayList(); - currentPlaylistNum = 0; + if (current.isMusic()) { + if (shuffleMusic) { + buildShuffledPlayList(); + currentPlaylistNum = 0; + } + SharedMediaQuery.loadMusic(current.getDialogId(), playlist.get(0).getId()); } - SharedMediaQuery.loadMusic(current.getDialogId(), playlist.get(0).getId()); return playAudio(current); } @@ -1597,7 +1957,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (currentPlaylistNum >= currentPlayList.size()) { currentPlaylistNum = 0; if (byStop && repeatMode == 0) { - stopProximitySensor(); if (audioPlayer != null || audioTrackPlayer != null) { if (audioPlayer != null) { try { @@ -1633,6 +1992,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel isPaused = true; playingMessageObject.audioProgress = 0.0f; playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); } return; @@ -1686,6 +2046,18 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } + public void setVoiceMessagesPlaylist(ArrayList playlist, boolean unread) { + voiceMessagesPlaylist = playlist; + if (voiceMessagesPlaylist != null) { + voiceMessagesPlaylistUnread = unread; + voiceMessagesPlaylistMap = new HashMap<>(); + for (int a = 0; a < voiceMessagesPlaylist.size(); a++) { + MessageObject messageObject = voiceMessagesPlaylist.get(a); + voiceMessagesPlaylistMap.put(messageObject.getId(), messageObject); + } + } + } + public boolean playAudio(MessageObject messageObject) { if (messageObject == null) { return false; @@ -1694,12 +2066,19 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (isPaused) { resumeAudio(messageObject); } + if (!raiseToSpeak) { + startRaiseToEarSensors(raiseChat); + } return true; } - if (audioTrackPlayer != null) { - MusicPlayerService.setIgnoreAudioFocus(); + if (!messageObject.isOut() && messageObject.isContentUnread() && messageObject.messageOwner.to_id.channel_id == 0) { + MessagesController.getInstance().markMessageContentAsRead(messageObject); } - cleanupPlayer(!playMusicAgain, false); + boolean notify = !playMusicAgain; + if (playingMessageObject != null) { + notify = false; + } + cleanupPlayer(notify, false); playMusicAgain = false; File file = null; if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() > 0) { @@ -1760,7 +2139,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel audioTrackPlayer.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() { @Override public void onMarkerReached(AudioTrack audioTrack) { - cleanupPlayer(true, true); + cleanupPlayer(true, true, true); } @Override @@ -1769,10 +2148,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } }); audioTrackPlayer.play(); - startProgressTimer(); - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - startProximitySensor(); - } } catch (Exception e) { FileLog.e("tmessages", e); if (audioTrackPlayer != null) { @@ -1802,12 +2177,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel }); audioPlayer.prepare(); audioPlayer.start(); - startProgressTimer(); - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { + if (messageObject.isVoice()) { audioInfo = null; playlist.clear(); shuffledPlaylist.clear(); - startProximitySensor(); } else { try { audioInfo = AudioInfo.getAudioInfo(cacheFile); @@ -1828,11 +2201,19 @@ public class MediaController implements NotificationCenter.NotificationCenterDel return false; } } + if (!hasAudioFoces) { + hasAudioFoces = true; + NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } isPaused = false; lastProgress = 0; lastPlayPcm = 0; playingMessageObject = messageObject; + if (!raiseToSpeak) { + startRaiseToEarSensors(raiseChat); + } + startProgressTimer(playingMessageObject); NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidStarted, messageObject); if (audioPlayer != null) { @@ -1844,6 +2225,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } catch (Exception e2) { playingMessageObject.audioProgress = 0; playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); FileLog.e("tmessages", e2); } } else if (audioTrackPlayer != null) { @@ -1871,7 +2253,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel }); } - if (playingMessageObject.messageOwner.media.document != null) { + if (playingMessageObject.isMusic()) { Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); ApplicationLoader.applicationContext.startService(intent); } else { @@ -1883,7 +2265,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } public void stopAudio() { - stopProximitySensor(); if (audioTrackPlayer == null && audioPlayer == null || playingMessageObject == null) { return; } @@ -1964,7 +2345,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } public boolean pauseAudio(MessageObject messageObject) { - stopProximitySensor(); if (audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.getId() != messageObject.getId()) { return false; } @@ -1989,17 +2369,19 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.getId() != messageObject.getId()) { return false; } - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - startProximitySensor(); - } + try { - startProgressTimer(); + startProgressTimer(messageObject); if (audioPlayer != null) { audioPlayer.start(); } else if (audioTrackPlayer != null) { audioTrackPlayer.play(); checkPlayerQueue(); } + if (!hasAudioFoces) { + hasAudioFoces = true; + NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } isPaused = false; NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); } catch (Exception e) { @@ -2030,7 +2412,8 @@ public class MediaController implements NotificationCenter.NotificationCenterDel try { Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); - v.vibrate(20); + v.vibrate(50); + //NotificationsController.getInstance().playRecordSound(); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -2049,11 +2432,13 @@ public class MediaController implements NotificationCenter.NotificationCenterDel return; } - recordingAudio = new TLRPC.TL_audio(); + recordingAudio = new TLRPC.TL_document(); recordingAudio.dc_id = Integer.MIN_VALUE; recordingAudio.id = UserConfig.lastLocalId; recordingAudio.user_id = UserConfig.getClientUserId(); recordingAudio.mime_type = "audio/ogg"; + recordingAudio.thumb = new TLRPC.TL_photoSizeEmpty(); + recordingAudio.thumb.type = "s"; UserConfig.lastLocalId--; UserConfig.saveConfig(false); @@ -2070,9 +2455,14 @@ public class MediaController implements NotificationCenter.NotificationCenterDel }); return; } - audioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize * 10); + //if (Build.VERSION.SDK_INT >= 11) { + // audioRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize * 10); + //} else { + audioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize * 10); + //} recordStartTime = System.currentTimeMillis(); recordTimeCount = 0; + samplesCount = 0; recordDialogId = dialog_id; recordReplyingMessageObject = reply_to_msg; recordAsAdmin = asAdmin; @@ -2111,12 +2501,65 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } }); } - }, paused ? 500 : 0); + }, paused ? 500 : 50); } - private void stopRecordingInternal(final boolean send) { - if (send) { - final TLRPC.TL_audio audioToSend = recordingAudio; + public void generateWaveform(MessageObject messageObject) { + final String id = messageObject.getId() + "_" + messageObject.getDialogId(); + final String path = FileLoader.getPathToMessage(messageObject.messageOwner).getAbsolutePath(); + /*for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { TODO if old attribute + TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.waveform == null || attribute.waveform.length == 0) { + attribute.waveform = MediaController.getInstance().getWaveform(path.getAbsolutePath()); + } + if (attribute.waveform != null) { + hasWaveform = true; + } + seekBarWaveform.setWaveform(attribute.waveform); + break; + } + }*/ + if (generatingWaveform.containsKey(id)) { + return; + } + generatingWaveform.put(id, messageObject); + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + final byte[] waveform = MediaController.getInstance().getWaveform(path); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessageObject messageObject = generatingWaveform.remove(id); + if (messageObject == null) { + return; + } + if (waveform != null) { + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + attribute.waveform = waveform; + attribute.flags |= 4; + break; + } + } + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + messagesRes.messages.add(messageObject.messageOwner); + MessagesStorage.getInstance().putMessages(messagesRes, messageObject.getDialogId(), -1, 0, 0, false); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(messageObject); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, messageObject.getDialogId(), arrayList); + } + } + }); + } + }); + } + + private void stopRecordingInternal(final int send) { + if (send != 0) { + final TLRPC.TL_document audioToSend = recordingAudio; final File recordingAudioFileToSend = recordingAudioFile; fileEncodingQueue.postRunnable(new Runnable() { @Override @@ -2127,11 +2570,20 @@ public class MediaController implements NotificationCenter.NotificationCenterDel public void run() { audioToSend.date = ConnectionsManager.getInstance().getCurrentTime(); audioToSend.size = (int) recordingAudioFileToSend.length(); + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.voice = true; + attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); //getWaveform(recordingAudioFileToSend.getAbsolutePath()); + if (attributeAudio.waveform != null) { + attributeAudio.flags |= 4; + } long duration = recordTimeCount; - audioToSend.duration = (int) (duration / 1000); + attributeAudio.duration = (int) (recordTimeCount / 1000); + audioToSend.attributes.add(attributeAudio); if (duration > 700) { - SendMessagesHelper.getInstance().sendMessage(audioToSend, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMessageObject, recordAsAdmin); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidSent); + if (send == 1) { + SendMessagesHelper.getInstance().sendMessage(audioToSend, null, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMessageObject, recordAsAdmin, null); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidSent, send == 2 ? audioToSend : null, send == 2 ? recordingAudioFileToSend.getAbsolutePath() : null); } else { recordingAudioFileToSend.delete(); } @@ -2152,9 +2604,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel recordingAudioFile = null; } - public void stopRecording(final boolean send) { + public void stopRecording(final int send) { if (recordStartRunnable != null) { recordQueue.cancelRunnable(recordStartRunnable); + recordStartRunnable = null; } recordQueue.postRunnable(new Runnable() { @Override @@ -2171,12 +2624,12 @@ public class MediaController implements NotificationCenter.NotificationCenterDel recordingAudioFile.delete(); } } - if (!send) { - stopRecordingInternal(false); + if (send == 0) { + stopRecordingInternal(0); } try { Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); - v.vibrate(20); + v.vibrate(50); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -2442,6 +2895,14 @@ public class MediaController implements NotificationCenter.NotificationCenterDel editor.commit(); } + public void toogleRaiseToSpeak() { + raiseToSpeak = !raiseToSpeak; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("raise_to_speak", raiseToSpeak); + editor.commit(); + } + public void checkSaveToGalleryFiles() { try { File telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram"); @@ -2478,6 +2939,10 @@ public class MediaController implements NotificationCenter.NotificationCenterDel return autoplayGifs; } + public boolean canRaiseToSpeak() { + return raiseToSpeak; + } + public static void loadGalleryPhotosAlbums(final int guid) { new Thread(new Runnable() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 305818bb8..aa34a3758 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -64,6 +64,8 @@ public class MessageObject { public int textHeight; public int blockHeight = Integer.MAX_VALUE; + private boolean layoutCreated; + public static Pattern urlPattern; public static class TextLayoutBlock { @@ -96,15 +98,18 @@ public class MessageObject { replyMessageObject = new MessageObject(message.replyMessage, users, chats, false); } + TLRPC.User fromUser = null; + if (isFromUser()) { + if (users != null) { + fromUser = users.get(message.from_id); + } + if (fromUser == null) { + fromUser = MessagesController.getInstance().getUser(message.from_id); + } + } + if (message instanceof TLRPC.TL_messageService) { if (message.action != null) { - TLRPC.User fromUser = null; - if (users != null) { - fromUser = users.get(message.from_id); - } - if (fromUser == null) { - fromUser = MessagesController.getInstance().getUser(message.from_id); - } if (message.action instanceof TLRPC.TL_messageActionChatCreate) { if (isOut()) { messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup); @@ -357,8 +362,10 @@ public class MessageObject { } else if (!isMediaEmpty()) { if (message.media instanceof TLRPC.TL_messageMediaPhoto) { messageText = LocaleController.getString("AttachPhoto", R.string.AttachPhoto); - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (isVideo()) { messageText = LocaleController.getString("AttachVideo", R.string.AttachVideo); + } else if (isVoice()) { + messageText = LocaleController.getString("AttachAudio", R.string.AttachAudio); } else if (message.media instanceof TLRPC.TL_messageMediaGeo || message.media instanceof TLRPC.TL_messageMediaVenue) { messageText = LocaleController.getString("AttachLocation", R.string.AttachLocation); } else if (message.media instanceof TLRPC.TL_messageMediaContact) { @@ -385,8 +392,6 @@ public class MessageObject { messageText = LocaleController.getString("AttachDocument", R.string.AttachDocument); } } - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - messageText = LocaleController.getString("AttachAudio", R.string.AttachAudio); } } else { messageText = message.message; @@ -394,9 +399,6 @@ public class MessageObject { if (messageText == null) { messageText = ""; } - if (generateLayout) { - messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); - } if (message instanceof TLRPC.TL_message || message instanceof TLRPC.TL_messageForwarded_old2) { if (isMediaEmpty()) { @@ -409,9 +411,11 @@ public class MessageObject { } else if (message.media instanceof TLRPC.TL_messageMediaGeo || message.media instanceof TLRPC.TL_messageMediaVenue) { contentType = 1; type = 4; - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (isVideo()) { contentType = 1; type = 3; + } else if (isVoice()) { + contentType = type = 2; } else if (message.media instanceof TLRPC.TL_messageMediaContact) { contentType = 3; type = 12; @@ -433,8 +437,6 @@ public class MessageObject { } else { type = 9; } - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - contentType = type = 2; } } else if (message instanceof TLRPC.TL_messageService) { if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { @@ -468,18 +470,32 @@ public class MessageObject { //dateKey = "0_0_0"; } - if (messageOwner.message != null && messageOwner.id < 0 && messageOwner.message.length() > 6 && messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + if (messageOwner.message != null && messageOwner.id < 0 && messageOwner.message.length() > 6 && isVideo()) { videoEditedInfo = new VideoEditedInfo(); videoEditedInfo.parseString(messageOwner.message); } generateCaption(); if (generateLayout) { - generateLayout(); + messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + generateLayout(fromUser); } + layoutCreated = generateLayout; generateThumbs(false); } + public void checkLayout() { + if (!layoutCreated) { + layoutCreated = true; + TLRPC.User fromUser = null; + if (isFromUser()) { + fromUser = MessagesController.getInstance().getUser(messageOwner.from_id); + } + messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + generateLayout(fromUser); + } + } + public static boolean isGifDocument(TLRPC.Document document) { return document != null && document.thumb != null && document.mime_type != null && (document.mime_type.equals("image/gif") || isNewGifDocument(document)); } @@ -535,14 +551,6 @@ public class MessageObject { } } } - } else if (messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - if (!update) { - photoThumbs = new ArrayList<>(); - photoThumbs.add(messageOwner.media.video.thumb); - } else if (photoThumbs != null && !photoThumbs.isEmpty() && messageOwner.media.video.thumb != null) { - TLRPC.PhotoSize photoObject = photoThumbs.get(0); - photoObject.location = messageOwner.media.video.thumb.location; - } } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { if (!(messageOwner.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) { if (!update) { @@ -644,12 +652,8 @@ public class MessageObject { } public String getFileName() { - if (messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - return FileLoader.getAttachFileName(messageOwner.media.video); - } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { return FileLoader.getAttachFileName(messageOwner.media.document); - } else if (messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - return FileLoader.getAttachFileName(messageOwner.media.audio); } else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { ArrayList sizes = messageOwner.media.photo.sizes; if (sizes.size() > 0) { @@ -663,12 +667,12 @@ public class MessageObject { } public int getFileType() { - if (messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + if (isVideo()) { return FileLoader.MEDIA_DIR_VIDEO; + } else if (isVoice()) { + return FileLoader.MEDIA_DIR_AUDIO; } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { return FileLoader.MEDIA_DIR_DOCUMENT; - } else if (messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - return FileLoader.MEDIA_DIR_AUDIO; } else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { return FileLoader.MEDIA_DIR_IMAGE; } @@ -772,7 +776,7 @@ public class MessageObject { private static void addUsernamesAndHashtags(CharSequence charSequence, boolean botCommands) { try { if (urlPattern == null) { - urlPattern = Pattern.compile("(^|\\s)/[a-zA-Z@\\d_]{1,255}|(^|\\s)@[a-zA-Z\\d_]{3,32}|(^|\\s)#[\\w\\.]+"); + urlPattern = Pattern.compile("(^|\\s)/[a-zA-Z@\\d_]{1,255}|(^|\\s)@[a-zA-Z\\d_]{1,32}|(^|\\s)#[\\w\\.]+"); } Matcher matcher = urlPattern.matcher(charSequence); while (matcher.find()) { @@ -822,7 +826,7 @@ public class MessageObject { } } - private void generateLayout() { + private void generateLayout(TLRPC.User fromUser) { if (type != 0 || messageOwner.to_id == null || messageText == null || messageText.length() == 0) { return; } @@ -856,6 +860,7 @@ public class MessageObject { if (messageText instanceof Spannable) { Spannable spannable = (Spannable) messageText; int count = messageOwner.entities.size(); + URLSpan[] spans = spannable.getSpans(0, messageText.length(), URLSpan.class); for (int a = 0; a < count; a++) { TLRPC.MessageEntity entity = messageOwner.entities.get(a); if (entity.length <= 0 || entity.offset < 0 || entity.offset >= messageOwner.message.length()) { @@ -863,6 +868,19 @@ public class MessageObject { } else if (entity.offset + entity.length > messageOwner.message.length()) { entity.length = messageOwner.message.length() - entity.offset; } + if (spans != null && spans.length > 0) { + for (int b = 0; b < spans.length; b++) { + if (spans[b] == null) { + continue; + } + int start = spannable.getSpanStart(spans[b]); + int end = spannable.getSpanEnd(spans[b]); + if (entity.offset <= start && entity.offset + entity.length >= start || entity.offset <= end && entity.offset + entity.length >= end) { + spannable.removeSpan(spans[b]); + spans[b] = null; + } + } + } if (entity instanceof TLRPC.TL_messageEntityBold) { spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (entity instanceof TLRPC.TL_messageEntityItalic) { @@ -904,6 +922,9 @@ public class MessageObject { maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); } } + if (fromUser != null && fromUser.bot) { + maxWidth -= AndroidUtilities.dp(20); + } StaticLayout textLayout; @@ -1056,7 +1077,11 @@ public class MessageObject { } public boolean isOutOwner() { - return messageOwner.out && messageOwner.from_id > 0; + return messageOwner.out && messageOwner.from_id > 0 && !messageOwner.post; + } + + public boolean isFromUser() { + return messageOwner.from_id > 0 && !messageOwner.post; } public boolean isUnread() { @@ -1100,9 +1125,7 @@ public class MessageObject { public boolean isSecretMedia() { return messageOwner instanceof TLRPC.TL_message_secret && - (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60 || - messageOwner.media instanceof TLRPC.TL_messageMediaAudio || - messageOwner.media instanceof TLRPC.TL_messageMediaVideo); + (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60 || isVoice() || isVideo()); } public static void setUnreadFlags(TLRPC.Message message, int flag) { @@ -1128,9 +1151,15 @@ public class MessageObject { public static boolean isImportant(TLRPC.Message message) { if (isMegagroup(message)) { - return message.from_id <= 0; + return message.post; } - return message.to_id.channel_id != 0 && (message.from_id <= 0 || message.mentioned || message.out || (message.flags & TLRPC.MESSAGE_FLAG_HAS_FROM_ID) == 0); + if (message.to_id.channel_id != 0) { + if (message instanceof TLRPC.TL_message_layer47 || message instanceof TLRPC.TL_message_old7) { + return message.to_id.channel_id != 0 && (message.from_id <= 0 || message.mentioned || message.out || (message.flags & TLRPC.MESSAGE_FLAG_HAS_FROM_ID) == 0); + } + return message.post; + } + return false; } public static boolean isMegagroup(TLRPC.Message message) { @@ -1200,9 +1229,10 @@ public class MessageObject { return ""; } - public static boolean isStickerMessage(TLRPC.Message message) { - if (message.media != null && message.media.document != null) { - for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) { + public static boolean isStickerDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { return true; } @@ -1211,17 +1241,60 @@ public class MessageObject { return false; } - public static boolean isMusicMessage(TLRPC.Message message) { - if (message.media != null && message.media.document != null) { - for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) { + public static boolean isVoiceDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { - return true; + return attribute.voice; } } } return false; } + public static boolean isVideoDocument(TLRPC.Document document) { + if (document != null) { + boolean isAnimated = false; + boolean isVideo = false; + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + isVideo = true; + } else if (attribute instanceof TLRPC.TL_documentAttributeAnimated) { + isAnimated = true; + } + } + return isVideo && !isAnimated; + } + return false; + } + + public static boolean isStickerMessage(TLRPC.Message message) { + return message.media != null && message.media.document != null && isStickerDocument(message.media.document); + } + + public static boolean isMusicMessage(TLRPC.Message message) { + if (message.media != null && message.media.document != null) { + for (int a = 0; a < message.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = message.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + return !attribute.voice; + } + } + } + return false; + } + + public static boolean isVoiceMessage(TLRPC.Message message) { + return message.media != null && message.media.document != null && isVoiceDocument(message.media.document); + } + + public static boolean isVideoMessage(TLRPC.Message message) { + return message.media != null && message.media.document != null && isVideoDocument(message.media.document); + /* && message.media.document.mime_type.equals("video/mp4")*/ + } + public static TLRPC.InputStickerSet getInputStickerSet(TLRPC.Message message) { if (message.media != null && message.media.document != null) { for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) { @@ -1339,6 +1412,14 @@ public class MessageObject { return isMusicMessage(messageOwner); } + public boolean isVoice() { + return isVoiceMessage(messageOwner); + } + + public boolean isVideo() { + return isVideoMessage(messageOwner); + } + public boolean isGif() { return isGifDocument(messageOwner.media.document); } @@ -1348,8 +1429,12 @@ public class MessageObject { } public String getMusicTitle() { - for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) { + for (int a = 0; a < messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageOwner.media.document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.voice) { + return LocaleController.formatDateAudio(messageOwner.date); + } String title = attribute.title; if (title == null || title.length() == 0) { title = FileLoader.getDocumentFileName(messageOwner.media.document); @@ -1364,8 +1449,30 @@ public class MessageObject { } public String getMusicAuthor() { - for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) { + for (int a = 0; a < messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageOwner.media.document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.voice) { + if (isOutOwner() || messageOwner.fwd_from != null && messageOwner.fwd_from.from_id == UserConfig.getClientUserId()) { + return LocaleController.getString("FromYou", R.string.FromYou); + } + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (messageOwner.fwd_from != null && messageOwner.fwd_from.channel_id != 0) { + chat = MessagesController.getInstance().getChat(messageOwner.fwd_from.channel_id); + } else if (messageOwner.fwd_from != null && messageOwner.fwd_from.from_id != 0) { + user = MessagesController.getInstance().getUser(messageOwner.fwd_from.from_id); + } else if (messageOwner.from_id < 0) { + chat = MessagesController.getInstance().getChat(-messageOwner.from_id); + } else { + user = MessagesController.getInstance().getUser(messageOwner.from_id); + } + if (user != null) { + return UserObject.getUserName(user); + } else if (chat != null) { + return chat.title; + } + } String performer = attribute.performer; if (performer == null || performer.length() == 0) { performer = LocaleController.getString("AudioUnknownArtist", R.string.AudioUnknownArtist); @@ -1381,11 +1488,15 @@ public class MessageObject { } public boolean isForwarded() { - return (messageOwner.flags & TLRPC.MESSAGE_FLAG_FWD) != 0; + return isForwardedMessage(messageOwner); + } + + public static boolean isForwardedMessage(TLRPC.Message message) { + return (message.flags & TLRPC.MESSAGE_FLAG_FWD) != 0; } public boolean isReply() { - return !(replyMessageObject != null && replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty) && messageOwner.reply_to_msg_id != 0 && (messageOwner.flags & TLRPC.MESSAGE_FLAG_REPLY) != 0; + return !(replyMessageObject != null && replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty) && (messageOwner.reply_to_msg_id != 0 || messageOwner.reply_to_random_id != 0) && (messageOwner.flags & TLRPC.MESSAGE_FLAG_REPLY) != 0; } public boolean isMediaEmpty() { @@ -1396,6 +1507,32 @@ public class MessageObject { return message == null || message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty || message.media instanceof TLRPC.TL_messageMediaWebPage; } + public boolean canEditMessage(TLRPC.Chat chat) { + return canEditMessage(messageOwner, chat); + } + + public static boolean canEditMessage(TLRPC.Message message, TLRPC.Chat chat) { + if (message.action != null && !(message.action instanceof TLRPC.TL_messageActionEmpty) || isForwardedMessage(message) || message.via_bot_id != 0 || message.id < 0 || Math.abs(message.date - ConnectionsManager.getInstance().getCurrentTime()) > MessagesController.getInstance().maxEditTime) { + return false; + } + if (chat == null && message.to_id.channel_id != 0) { + chat = MessagesController.getInstance().getChat(message.to_id.channel_id); + } + if (ChatObject.isChannel(chat) && chat.megagroup) { + return message.out; + } + if (ChatObject.isChannel(chat) && !chat.megagroup && (chat.creator || chat.editor && isOut(message)) && isImportant(message)) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto || + message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) || + message.media instanceof TLRPC.TL_messageMediaEmpty || + message.media instanceof TLRPC.TL_messageMediaWebPage || + message.media == null) { + return true; + } + } + return false; + } + public boolean canDeleteMessage(TLRPC.Chat chat) { return canDeleteMessage(messageOwner, chat); } @@ -1414,11 +1551,11 @@ public class MessageObject { if (chat.creator) { return true; } else if (chat.editor) { - if (isOut(message) || message.from_id > 0) { + if (isOut(message) || message.from_id > 0 && !message.post) { return true; } } else if (chat.moderator) { - if (message.from_id > 0) { + if (message.from_id > 0 && !message.post) { return true; } } else if (isOut(message) && message.from_id > 0) { @@ -1429,15 +1566,17 @@ public class MessageObject { } public String getForwardedName() { - if (messageOwner.fwd_from_id instanceof TLRPC.TL_peerChannel) { - TLRPC.Chat chat = MessagesController.getInstance().getChat(messageOwner.fwd_from_id.channel_id); - if (chat != null) { - return chat.title; - } - } else if (messageOwner.fwd_from_id instanceof TLRPC.TL_peerUser) { - TLRPC.User user = MessagesController.getInstance().getUser(messageOwner.fwd_from_id.user_id); - if (user != null) { - return UserObject.getUserName(user); + if (messageOwner.fwd_from != null) { + if (messageOwner.fwd_from.channel_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageOwner.fwd_from.channel_id); + if (chat != null) { + return chat.title; + } + } else if (messageOwner.fwd_from.from_id != 0) { + TLRPC.User user = MessagesController.getInstance().getUser(messageOwner.fwd_from.from_id); + if (user != null) { + return UserObject.getUserName(user); + } } } return null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index 769784be6..c8080cc57 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -61,6 +61,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public ConcurrentHashMap dialogs_read_inbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); public ConcurrentHashMap dialogs_dict = new ConcurrentHashMap<>(100, 1.0f, 2); public HashMap dialogMessage = new HashMap<>(); + public HashMap dialogMessagesByRandomIds = new HashMap<>(); public HashMap dialogMessagesByIds = new HashMap<>(); public ConcurrentHashMap> printingUsers = new ConcurrentHashMap<>(20, 1.0f, 2); public HashMap printingStrings = new HashMap<>(); @@ -69,6 +70,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter public ConcurrentHashMap onlinePrivacy = new ConcurrentHashMap<>(20, 1.0f, 2); private int lastPrintingStringCount = 0; + private long lastCreatedDialogId; + private SparseIntArray shortPollChannels = new SparseIntArray(); private SparseIntArray needShortPollChannels = new SparseIntArray(); @@ -97,6 +100,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter private ArrayList loadedFullParticipants = new ArrayList<>(); private ArrayList loadedFullChats = new ArrayList<>(); + private HashMap> reloadingWebpages = new HashMap<>(); + private HashMap> reloadingWebpagesPending = new HashMap<>(); + private HashMap> reloadingMessages = new HashMap<>(); private boolean gettingNewDeleteTask = false; @@ -112,6 +118,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter public boolean firstGettingTask = false; public boolean registeringForPush = false; + public int secretWebpagePreview = 2; + private long lastStatusUpdateTime = 0; private int statusRequest = 0; private int statusSettingState = 0; @@ -124,6 +132,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public int maxBroadcastCount = 100; public int maxMegagroupCount = 1000; public int minGroupConvertSize = 200; + public int maxEditTime = 172800; public int groupBigSize; private ArrayList disabledFeatures = new ArrayList<>(); @@ -186,8 +195,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter enableJoined = preferences.getBoolean("EnableContactJoined", true); preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + secretWebpagePreview = preferences.getInt("secretWebpage2", 2); maxGroupCount = preferences.getInt("maxGroupCount", 200); maxMegagroupCount = preferences.getInt("maxMegagroupCount", 1000); + maxEditTime = preferences.getInt("maxEditTime", 3600); groupBigSize = preferences.getInt("groupBigSize", 10); fontSize = preferences.getInt("fons_size", AndroidUtilities.isTablet() ? 18 : 16); String disabledFeaturesString = preferences.getString("disabledFeatures", null); @@ -219,6 +230,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter maxGroupCount = config.chat_size_max; groupBigSize = config.chat_big_size; disabledFeatures = config.disabled_features; + maxEditTime = config.edit_time_limit; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); @@ -226,6 +238,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter //editor.putInt("maxBroadcastCount", maxBroadcastCount); editor.putInt("maxMegagroupCount", maxMegagroupCount); editor.putInt("groupBigSize", groupBigSize); + editor.putInt("maxEditTime", maxEditTime); try { SerializedData data = new SerializedData(); data.writeInt32(disabledFeatures.size()); @@ -452,6 +465,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter SecretChatHelper.getInstance().cleanUp(); StickersQuery.cleanup(); + reloadingWebpages.clear(); + reloadingWebpagesPending.clear(); dialogs_dict.clear(); dialogs_read_inbox_max.clear(); exportedChats.clear(); @@ -461,6 +476,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter channelViewsToReload.clear(); dialogsServerOnly.clear(); dialogsGroupsOnly.clear(); + dialogMessagesByIds.clear(); + dialogMessagesByRandomIds.clear(); users.clear(); usersByUsernames.clear(); chats.clear(); @@ -480,6 +497,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter updatesStartWaitTimeSeq = 0; updatesStartWaitTimePts = 0; updatesStartWaitTimeQts = 0; + lastCreatedDialogId = 0; gettingDifference = false; } }); @@ -573,6 +591,19 @@ public class MessagesController implements NotificationCenter.NotificationCenter return chat; } + public void setLastCreatedDialogId(final long dialog_id, final boolean set) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (set) { + lastCreatedDialogId = dialog_id; + } else if (lastCreatedDialogId == dialog_id) { + lastCreatedDialogId = 0; + } + } + }); + } + public TLRPC.ExportedChatInvite getExportedInvite(int chat_id) { return exportedChats.get(chat_id); } @@ -589,17 +620,47 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (user.username != null && user.username.length() > 0) { usersByUsernames.put(user.username.toLowerCase(), user); } - if (!fromCache) { - users.put(user.id, user); - if (user.id == UserConfig.getClientUserId()) { - UserConfig.setCurrentUser(user); - UserConfig.saveConfig(true); + if (user.min) { + if (oldUser != null) { + if (!fromCache) { + if (user.first_name != null) { + oldUser.first_name = user.first_name; + oldUser.flags |= 2; + } else { + oldUser.first_name = null; + oldUser.flags = oldUser.flags &~ 2; + } + if (user.last_name != null) { + oldUser.last_name = user.last_name; + oldUser.flags |= 4; + } else { + oldUser.last_name = null; + oldUser.flags = oldUser.flags &~ 4; + } + if (user.photo != null) { + oldUser.photo = user.photo; + oldUser.flags |= 32; + } else { + oldUser.photo = null; + oldUser.flags = oldUser.flags &~ 32; + } + } + } else { + users.put(user.id, user); } - if (oldUser != null && user.status != null && oldUser.status != null && user.status.expires != oldUser.status.expires) { - return true; + } else { + if (!fromCache) { + users.put(user.id, user); + if (user.id == UserConfig.getClientUserId()) { + UserConfig.setCurrentUser(user); + UserConfig.saveConfig(true); + } + if (oldUser != null && user.status != null && oldUser.status != null && user.status.expires != oldUser.status.expires) { + return true; + } + } else if (oldUser == null) { + users.put(user.id, user); } - } else if (oldUser == null) { - users.put(user.id, user); } return false; } @@ -854,7 +915,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter } final ArrayList objects = new ArrayList<>(); - ArrayList messagesToReload = null; for (int a = 0; a < messagesRes.messages.size(); a++) { TLRPC.Message message = messagesRes.messages.get(a); if (chat != null && chat.megagroup) { @@ -1283,7 +1343,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter return; } if (channelId == 0) { - for (Integer id : messages) { + for (int a = 0; a < messages.size(); a++) { + Integer id = messages.get(a); MessageObject obj = dialogMessagesByIds.get(id); if (obj != null) { obj.deleted = true; @@ -1292,7 +1353,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { MessageObject obj = dialogMessage.get((long) -channelId); if (obj != null) { - for (Integer id : messages) { + for (int a = 0; a < messages.size(); a++) { + Integer id = messages.get(a); if (obj.getId() == id) { obj.deleted = true; break; @@ -1301,7 +1363,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } ArrayList toSend = new ArrayList<>(); - for (Integer mid : messages) { + for (int a = 0; a < messages.size(); a++) { + Integer mid = messages.get(a); if (mid > 0) { toSend.add(mid); } @@ -1382,7 +1445,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialog.unread_count = 0; } dialogMessage.remove(dialog.id); - dialogMessagesByIds.remove(dialog.top_message); + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } dialog.top_message = 0; } NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); @@ -1940,6 +2006,62 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } + public void reloadWebPages(final long dialog_id, HashMap> webpagesToReload) { + //if (secretWebpagePreview != 1) { + // return; + //} + for (HashMap.Entry> entry : webpagesToReload.entrySet()) { + final String url = entry.getKey(); + final ArrayList messages = entry.getValue(); + ArrayList arrayList = reloadingWebpages.get(url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + reloadingWebpages.put(url, arrayList); + } + arrayList.addAll(messages); + TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); + req.message = url; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList arrayList = reloadingWebpages.remove(url); + if (arrayList == null) { + return; + } + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + if (!(response instanceof TLRPC.TL_messageMediaWebPage)) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = new TLRPC.TL_webPageEmpty(); + messagesRes.messages.add(arrayList.get(a).messageOwner); + } + } else { + TLRPC.TL_messageMediaWebPage media = (TLRPC.TL_messageMediaWebPage) response; + if (media.webpage instanceof TLRPC.TL_webPage || media.webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = media.webpage; + if (a == 0) { + ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); + } + messagesRes.messages.add(arrayList.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(media.webpage.id, arrayList); + } + } + if (!messagesRes.messages.isEmpty()) { + MessagesStorage.getInstance().putMessages(messagesRes, dialog_id, -2, 0, 0, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + }); + } + }); + } + } + public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, final int first_unread, final int last_message_id, final int unread_count, final int last_date, final int load_type, final int important, final boolean isEnd, final int loadIndex, final boolean queryFromServer) { Utilities.stageQueue.postRunnable(new Runnable() { @@ -1994,7 +2116,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!isCache) { for (int a = 0; a < size; a++) { TLRPC.Message message = messagesRes.messages.get(a); - if (!isCache && message.from_id <= 0 && !message.out) { + if (!isCache && message.post && !message.out) { message.media_unread = true; } if (isMegagroup) { @@ -2014,11 +2136,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter } final ArrayList objects = new ArrayList<>(); final ArrayList messagesToReload = new ArrayList<>(); + final HashMap> webpagesToReload = new HashMap<>(); TLRPC.InputChannel inputChannel = null; for (int a = 0; a < size; a++) { TLRPC.Message message = messagesRes.messages.get(a); message.dialog_id = dialog_id; - objects.add(new MessageObject(message, usersDict, chatsDict, true)); + MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, true); + objects.add(messageObject); if (isCache) { if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { if (message.media.bytes != null && (message.media.bytes.length == 0 || message.media.bytes.length == 1 && message.media.bytes[0] < TLRPC.LAYER)) { @@ -2027,6 +2151,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { if (message.media.webpage instanceof TLRPC.TL_webPagePending && message.media.webpage.date <= ConnectionsManager.getInstance().getCurrentTime()) { messagesToReload.add(message.id); + } else if (message.media.webpage instanceof TLRPC.TL_webPageUrlPending) { + ArrayList arrayList = webpagesToReload.get(message.media.webpage.url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + webpagesToReload.put(message.media.webpage.url, arrayList); + } + arrayList.add(messageObject); } } } @@ -2049,9 +2180,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter first_unread_final = first_unread; } NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, messagesRes.collapsed, isEnd, classGuid, loadIndex); - if (messagesToReload != null) { + if (!messagesToReload.isEmpty()) { reloadMessages(messagesToReload, dialog_id); } + if (!webpagesToReload.isEmpty()) { + reloadWebPages(dialog_id, webpagesToReload); + } } }); } @@ -2078,7 +2212,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (lower_id != 0 && high_id != 1 && dialog.top_message > 0) { MessageObject message = dialogMessage.get(dialog.id); if (message != null && message.getId() > 0) { - req.offset_date = message.messageOwner.date; + req.offset_date = Math.max(dialog.last_message_date_i, message.messageOwner.date); req.offset_id = message.messageOwner.id; int id; if (message.messageOwner.to_id.channel_id != 0) { @@ -2301,6 +2435,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter final HashMap new_dialogs_dict = new HashMap<>(); final HashMap new_dialogMessage = new HashMap<>(); + final HashMap notImportantDates = new HashMap<>(); final HashMap usersDict = new HashMap<>(); final HashMap chatsDict = new HashMap<>(); @@ -2319,6 +2454,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter for (int a = 0; a < dialogsRes.messages.size(); a++) { TLRPC.Message message = dialogsRes.messages.get(a); if (message.to_id.channel_id != 0) { + if (!MessageObject.isImportant(message)) { + notImportantDates.put(-message.to_id.channel_id, message.date); + } TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); if (chat != null && chat.left/* && !chat.megagroup*/) { continue; @@ -2332,7 +2470,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter continue; } } - if (!isCache && message.from_id <= 0 && !message.out) { + if (!isCache && message.post && !message.out) { message.media_unread = true; } MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, false); @@ -2356,6 +2494,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (d.id == 0) { continue; } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + if (d.last_message_date_i == 0 && d.top_not_important_message != 0) { + Integer date = notImportantDates.get((int) d.id); + if (date != null) { + d.last_message_date_i = date; + } + } if (d instanceof TLRPC.TL_dialogChannel) { TLRPC.Chat chat = chatsDict.get(-(int) d.id); if (chat != null && chat.megagroup) { @@ -2372,12 +2522,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter continue; } } - if (d.last_message_date == 0) { - MessageObject mess = new_dialogMessage.get(d.id); - if (mess != null) { - d.last_message_date = mess.messageOwner.date; - } - } new_dialogs_dict.put(d.id, d); Integer value = dialogs_read_inbox_max.get(d.id); @@ -2442,6 +2586,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, messageObject); if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } } } else { MessageObject oldMsg = dialogMessage.get(key); @@ -2452,6 +2599,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, messageObject); if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject != null && messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } } } } else { @@ -2461,6 +2617,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, newMsg); if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg != null && newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } } @@ -2538,16 +2701,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); int currentValue = preferences.getInt("notify2_" + dialog_id, 0); int currentValue2 = preferences.getInt("notifyuntil_" + dialog_id, 0); - SharedPreferences.Editor editor = null; + SharedPreferences.Editor editor = preferences.edit(); + boolean updated = false; TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); if (dialog != null) { dialog.notify_settings = notify_settings; } + editor.putBoolean("silent_" + dialog_id, notify_settings.silent); if (notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime()) { int until = 0; if (notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { if (currentValue != 2) { - editor = preferences.edit(); + updated = true; editor.putInt("notify2_" + dialog_id, 2); if (dialog != null) { dialog.notify_settings.mute_until = Integer.MAX_VALUE; @@ -2555,8 +2720,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } else { if (currentValue != 3 || currentValue2 != notify_settings.mute_until) { + updated = true; until = notify_settings.mute_until; - editor = preferences.edit(); editor.putInt("notify2_" + dialog_id, 3); editor.putInt("notifyuntil_" + dialog_id, notify_settings.mute_until); if (dialog != null) { @@ -2568,16 +2733,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter NotificationsController.getInstance().removeNotificationsForDialog(dialog_id); } else { if (currentValue != 0) { + updated = true; if (dialog != null) { dialog.notify_settings.mute_until = 0; } - editor = preferences.edit(); editor.remove("notify2_" + dialog_id); } MessagesStorage.getInstance().setDialogFlags(dialog_id, 0); } - if (editor != null) { - editor.commit(); + editor.commit(); + if (updated) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.notificationsSettingsUpdated); } } @@ -2599,6 +2764,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { dialog_id = -dialog.peer.channel_id; } + editor.putBoolean("silent_" + dialog_id, dialog.notify_settings.silent); if (dialog.notify_settings.mute_until != 0) { if (dialog.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { editor.putInt("notify2_" + dialog_id, 2); @@ -2723,6 +2889,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, messageObject); if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } } } else { currentDialog.unread_count = value.unread_count; @@ -2734,6 +2903,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, messageObject); if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } } } } else { @@ -2743,6 +2921,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(key, newMsg); if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } } @@ -2823,30 +3008,34 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } - public void markMessageContentAsRead(final TLRPC.Message message) { + public void markMessageContentAsRead(final MessageObject messageObject) { ArrayList arrayList = new ArrayList<>(); - long messageId = message.id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; + long messageId = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; } arrayList.add(messageId); MessagesStorage.getInstance().markMessagesContentAsRead(arrayList); - TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); - req.id.add(message.id); NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, arrayList); - ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; - processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + if (messageObject.getId() < 0) { + markMessageAsRead(messageObject.getDialogId(), messageObject.messageOwner.random_id, Integer.MIN_VALUE); + } else { + TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); + req.id.add(messageObject.getId()); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } } - } - }); + }); + } } public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) { - if (random_id == 0 || dialog_id == 0 || ttl <= 0) { + if (random_id == 0 || dialog_id == 0 || ttl <= 0 && ttl != Integer.MIN_VALUE) { return; } int lower_part = (int) dialog_id; @@ -2861,8 +3050,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter ArrayList random_ids = new ArrayList<>(); random_ids.add(random_id); SecretChatHelper.getInstance().sendMessagesReadMessage(chat, random_ids, null); - int time = ConnectionsManager.getInstance().getCurrentTime(); - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); + if (ttl > 0) { + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); + } } public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int max_date, final boolean was, final boolean popup) { @@ -2985,7 +3176,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public int createChat(String title, ArrayList selectedContacts, final String about, int type) { + public int createChat(String title, ArrayList selectedContacts, final String about, int type, final BaseFragment fragment) { if (type == ChatObject.CHAT_TYPE_BROADCAST) { TLRPC.TL_chat chat = new TLRPC.TL_chat(); chat.id = UserConfig.lastBroadcastId; @@ -3009,9 +3200,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter chatFull.participants.chat_id = chat.id; chatFull.participants.admin_id = UserConfig.getClientUserId(); chatFull.participants.version = 1; - for (Integer id : selectedContacts) { + for (int a = 0; a < selectedContacts.size(); a++) { TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant(); - participant.user_id = id; + participant.user_id = selectedContacts.get(a); participant.inviter_id = UserConfig.getClientUserId(); participant.date = (int) (System.currentTimeMillis() / 1000); chatFull.participants.participants.add(participant); @@ -3045,8 +3236,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (type == ChatObject.CHAT_TYPE_CHAT) { TLRPC.TL_messages_createChat req = new TLRPC.TL_messages_createChat(); req.title = title; - for (Integer uid : selectedContacts) { - TLRPC.User user = getUser(uid); + for (int a = 0; a < selectedContacts.size(); a++) { + TLRPC.User user = getUser(selectedContacts.get(a)); if (user == null) { continue; } @@ -3054,11 +3245,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter } return ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override - public void run(TLObject response, TLRPC.TL_error error) { + public void run(TLObject response, final TLRPC.TL_error error) { if (error != null) { AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { + AlertsCreator.showAddUserAlert(error.text, fragment, false); NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidFailCreate); } }); @@ -3213,6 +3405,20 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } + public void toogleChannelInvites(int chat_id, boolean enabled) { + TLRPC.TL_channels_toggleInvites req = new TLRPC.TL_channels_toggleInvites(); + req.channel = getInputChannel(chat_id); + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + public void toogleChannelComments(int chat_id, boolean enabled) { TLRPC.TL_channels_toggleComments req = new TLRPC.TL_channels_toggleComments(); req.channel = getInputChannel(chat_id); @@ -3233,6 +3439,26 @@ public class MessagesController implements NotificationCenter.NotificationCenter }, ConnectionsManager.RequestFlagInvokeAfter); } + public void toogleChannelSignatures(int chat_id, boolean enabled) { + TLRPC.TL_channels_toggleSignatures req = new TLRPC.TL_channels_toggleSignatures(); + req.channel = getInputChannel(chat_id); + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); + } + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + public void updateChannelAbout(int chat_id, final String about, final TLRPC.ChatFull info) { if (info == null) { return; @@ -3435,8 +3661,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } else { if (info instanceof TLRPC.TL_chatFull) { - for (TLRPC.ChatParticipant p : info.participants.participants) { - if (p.user_id == user.id) { + for (int a = 0; a < info.participants.participants.size(); a++) { + if (info.participants.participants.get(a).user_id == user.id) { return; } } @@ -3656,32 +3882,43 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void generateUpdateMessage() { - Utilities.stageQueue.postRunnable(new Runnable() { + if (UserConfig.lastUpdateVersion == null || UserConfig.lastUpdateVersion.equals(BuildVars.BUILD_VERSION_STRING)) { + return; + } + TLRPC.TL_help_getAppChangelog req = new TLRPC.TL_help_getAppChangelog(); + req.app_version = BuildVars.BUILD_VERSION_STRING; + try { + req.lang_code = LocaleController.getLocaleString(LocaleController.getInstance().getSystemDefaultLocale()); + req.device_model = Build.MANUFACTURER + Build.MODEL; + req.system_version = "SDK " + Build.VERSION.SDK_INT; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (req.lang_code == null || req.lang_code.trim().length() == 0) { + req.lang_code = "en"; + } + if (req.device_model == null || req.device_model.trim().length() == 0) { + req.device_model = "Android unknown"; + } + if (req.system_version == null || req.system_version.trim().length() == 0) { + req.system_version = "SDK Unknown"; + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override - public void run() { - try { - String build = LocaleController.getString("updateBuild", R.string.updateBuild); - if (build != null) { - int version = Utilities.parseInt(build); - if (version == 0) { - version = 524; - } - if (version <= UserConfig.lastUpdateVersion) { - return; - } - UserConfig.lastUpdateVersion = version; - UserConfig.saveConfig(false); - } + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + UserConfig.lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; + UserConfig.saveConfig(false); + } + if (response instanceof TLRPC.TL_help_appChangelog) { TLRPC.TL_updateServiceNotification update = new TLRPC.TL_updateServiceNotification(); - update.message = LocaleController.getString("updateText", R.string.updateText); + update.message = ((TLRPC.TL_help_appChangelog) response).text; update.media = new TLRPC.TL_messageMediaEmpty(); update.type = "update"; update.popup = false; ArrayList updates = new ArrayList<>(); updates.add(update); processUpdateArray(updates, null, null); - } catch (Exception e) { - FileLog.e("tmessages", e); } } }); @@ -4113,10 +4350,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.Message message = res.new_messages.get(a); if (!message.out) { message.unread = true; - if (message.from_id <= 0 || channelFinal != null && channelFinal.megagroup) { + if (message.post || channelFinal != null && channelFinal.megagroup) { message.media_unread = true; } } + if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } if (channelFinal != null && channelFinal.megagroup) { message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } @@ -4127,7 +4368,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter value = MessagesStorage.getInstance().getChannelReadInboxMax(channelId); } - MessageObject obj = new MessageObject(message, usersDict, true); + MessageObject obj = new MessageObject(message, usersDict, dialog_id == lastCreatedDialogId); if (channelFinal != null && channelFinal.left || value >= obj.getId()) { obj.setIsRead(); obj.setContentIsRead(); @@ -4187,10 +4428,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.dialog_id = -channelId; if (!message.out) { message.unread = true; - if (message.from_id <= 0 || channelFinal != null && channelFinal.megagroup) { + if (message.post || channelFinal != null && channelFinal.megagroup) { message.media_unread = true; } } + if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } if (channelFinal != null && channelFinal.megagroup) { message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } @@ -4204,7 +4449,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); - if (channelFinal.megagroup) { + if (channelFinal != null && channelFinal.megagroup) { res.unread_important_count = Math.max(res.unread_count, res.unread_important_count); res.top_important_message = Math.max(res.top_important_message, res.top_message); } @@ -4366,12 +4611,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.media_unread = false; } - MessageObject obj = new MessageObject(message, usersDict, chatsDict, true); - - if (!obj.isOut() && obj.isUnread()) { - pushMessages.add(obj); - } - long uid; if (message.dialog_id != 0) { uid = message.dialog_id; @@ -4385,6 +4624,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter uid = message.to_id.user_id; } } + + MessageObject obj = new MessageObject(message, usersDict, chatsDict, uid == lastCreatedDialogId); + + if (!obj.isOut() && obj.isUnread()) { + pushMessages.add(obj); + } + ArrayList arr = messages.get(uid); if (arr == null) { arr = new ArrayList<>(); @@ -4613,7 +4859,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter return 0; } else if (update instanceof TLRPC.TL_updateNewEncryptedMessage) { return 1; - } else if (update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateDeleteChannelMessages) { + } else if (update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateDeleteChannelMessages || update instanceof TLRPC.TL_updateEditChannelMessage) { return 2; } else { return 3; @@ -4642,20 +4888,23 @@ public class MessagesController implements NotificationCenter.NotificationCenter } boolean needFwdUser = false; - if (updates.fwd_from_id instanceof TLRPC.TL_peerUser) { - user2 = getUser(updates.fwd_from_id.user_id); - if (user2 == null) { - user2 = MessagesStorage.getInstance().getUserSync(updates.fwd_from_id.user_id); - putUser(user2, true); + if (updates.fwd_from != null) { + if (updates.fwd_from.from_id != 0) { + user2 = getUser(updates.fwd_from.from_id); + if (user2 == null) { + user2 = MessagesStorage.getInstance().getUserSync(updates.fwd_from.from_id); + putUser(user2, true); + } + needFwdUser = true; } - needFwdUser = true; - } else if (updates.fwd_from_id instanceof TLRPC.TL_peerChannel) { - channel = getChat(updates.fwd_from_id.channel_id); - if (channel == null) { - channel = MessagesStorage.getInstance().getChatSync(updates.fwd_from_id.channel_id); - putChat(channel, true); + if (updates.fwd_from.channel_id != 0) { + channel = getChat(updates.fwd_from.channel_id); + if (channel == null) { + channel = MessagesStorage.getInstance().getChatSync(updates.fwd_from.channel_id); + putChat(channel, true); + } + needFwdUser = true; } - needFwdUser = true; } boolean needBotUser = false; @@ -4705,6 +4954,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.to_id.chat_id = updates.chat_id; message.dialog_id = -updates.chat_id; } + message.fwd_from = updates.fwd_from; + message.silent = updates.silent; message.out = updates.out; message.unread = updates.unread; message.mentioned = updates.mentioned; @@ -4714,12 +4965,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter message.date = updates.date; message.via_bot_id = updates.via_bot_id; message.flags = updates.flags | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; - message.fwd_from_id = updates.fwd_from_id; - message.fwd_date = updates.fwd_date; message.reply_to_msg_id = updates.reply_to_msg_id; message.media = new TLRPC.TL_messageMediaEmpty(); MessagesStorage.lastPtsValue = updates.pts; - final MessageObject obj = new MessageObject(message, null, true); + final MessageObject obj = new MessageObject(message, null, message.dialog_id == lastCreatedDialogId); final ArrayList objArr = new ArrayList<>(); objArr.add(obj); ArrayList arr = new ArrayList<>(); @@ -4874,6 +5123,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter int channelId; if (update instanceof TLRPC.TL_updateNewChannelMessage) { channelId = ((TLRPC.TL_updateNewChannelMessage) update).message.to_id.channel_id; + } else if (update instanceof TLRPC.TL_updateEditChannelMessage) { + channelId = ((TLRPC.TL_updateEditChannelMessage) update).message.to_id.channel_id; } else { channelId = update.channel_id; } @@ -5049,6 +5300,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter final HashMap webPages = new HashMap<>(); final ArrayList pushMessages = new ArrayList<>(); final ArrayList messagesArr = new ArrayList<>(); + final HashMap> editingMessages = new HashMap<>(); final SparseArray channelViews = new SparseArray<>(); final SparseArray> channelsGroups = new SparseArray<>(); final SparseArray markAsReadMessagesInbox = new SparseArray<>(); @@ -5139,7 +5391,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter TLRPC.User user = usersDict.get(message.action.user_id); if (user != null && user.bot) { message.reply_markup = new TLRPC.TL_replyKeyboardHide(); - } else if (message.action.user_id == UserConfig.getClientUserId()) { + } else if (message.from_id == UserConfig.getClientUserId() && message.action.user_id == UserConfig.getClientUserId()) { continue; } } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { @@ -5149,7 +5401,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (update instanceof TLRPC.TL_updateNewChannelMessage) { if (message.to_id.channel_id != 0 && !message.out) { message.unread = true; - if (message.from_id <= 0 || (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + if (message.post || (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { message.media_unread = true; } } @@ -5166,12 +5418,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter } messagesArr.add(message); ImageLoader.saveMessageThumbs(message); - MessageObject obj = new MessageObject(message, usersDict, chatsDict, true); - if (obj.type == 11) { - interfaceUpdateMask |= UPDATE_MASK_CHAT_AVATAR; - } else if (obj.type == 10) { - interfaceUpdateMask |= UPDATE_MASK_CHAT_NAME; - } if (message.to_id.chat_id != 0) { message.dialog_id = -message.to_id.chat_id; } else if (message.to_id.channel_id != 0) { @@ -5182,6 +5428,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter } message.dialog_id = message.to_id.user_id; } + MessageObject obj = new MessageObject(message, usersDict, chatsDict, message.dialog_id == lastCreatedDialogId); + if (obj.type == 11) { + interfaceUpdateMask |= UPDATE_MASK_CHAT_AVATAR; + } else if (obj.type == 10) { + interfaceUpdateMask |= UPDATE_MASK_CHAT_NAME; + } ArrayList arr = messages.get(message.dialog_id); if (arr == null) { arr = new ArrayList<>(); @@ -5297,7 +5549,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.dialog_id = update.user_id; messagesArr.add(newMessage); - MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, true); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, newMessage.dialog_id == lastCreatedDialogId); ArrayList arr = messages.get(newMessage.dialog_id); if (arr == null) { arr = new ArrayList<>(); @@ -5345,7 +5597,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.dialog_id = 777000; messagesArr.add(newMessage); - MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, true); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, newMessage.dialog_id == lastCreatedDialogId); ArrayList arr = messages.get(newMessage.dialog_id); if (arr == null) { arr = new ArrayList<>(); @@ -5365,10 +5617,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter arr = new ArrayList<>(); messages.put(uid, arr); } - for (TLRPC.Message message : decryptedMessages) { + for (int a = 0; a < decryptedMessages.size(); a++) { + TLRPC.Message message = decryptedMessages.get(a); ImageLoader.saveMessageThumbs(message); messagesArr.add(message); - MessageObject obj = new MessageObject(message, usersDict, chatsDict, true); + MessageObject obj = new MessageObject(message, usersDict, chatsDict, uid == lastCreatedDialogId); arr.add(obj); pushMessages.add(obj); } @@ -5462,7 +5715,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.message = notification.message; messagesArr.add(newMessage); - MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, true); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, newMessage.dialog_id == lastCreatedDialogId); ArrayList arr = messages.get(newMessage.dialog_id); if (arr == null) { arr = new ArrayList<>(); @@ -5522,6 +5775,45 @@ public class MessagesController implements NotificationCenter.NotificationCenter updatesOnMainThread.add(update); } else if (update instanceof TLRPC.TL_updateSavedGifs) { updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateEditChannelMessage) { + TLRPC.Message message = ((TLRPC.TL_updateEditChannelMessage) update).message; + if (message.to_id.channel_id != 0 && !message.out) { + message.unread = true; + if (message.post || (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + message.media_unread = true; + } + } + + long dialog_id = -update.channel_id; + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance().getChannelReadInboxMax(update.channel_id); + } + if (value >= message.id) { + message.unread = false; + message.media_unread = false; + } + + ImageLoader.saveMessageThumbs(message); + + if (message.to_id.chat_id != 0) { + message.dialog_id = -message.to_id.chat_id; + } else if (message.to_id.channel_id != 0) { + message.dialog_id = -message.to_id.channel_id; + } else { + if (message.to_id.user_id == UserConfig.getClientUserId()) { + message.to_id.user_id = message.from_id; + } + message.dialog_id = message.to_id.user_id; + } + MessageObject obj = new MessageObject(message, usersDict, chatsDict, message.dialog_id == lastCreatedDialogId); + + ArrayList arr = editingMessages.get(message.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + editingMessages.put(message.dialog_id, arr); + } + arr.add(obj); } } if (!messages.isEmpty()) { @@ -5562,6 +5854,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!messagesArr.isEmpty()) { MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); } + if (!editingMessages.isEmpty()) { + for (HashMap.Entry> pair : editingMessages.entrySet()) { + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + ArrayList messageObjects = pair.getValue(); + for (int a = 0; a < messageObjects.size(); a++) { + messagesRes.messages.add(messageObjects.get(a).messageOwner); + } + MessagesStorage.getInstance().putMessages(messagesRes, pair.getKey(), -2, 0, 0, false); + } + } if (channelViews.size() != 0) { MessagesStorage.getInstance().putChannelViews(channelViews, true); @@ -5586,7 +5888,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter final TLRPC.User currentUser = getUser(update.user_id); if (update instanceof TLRPC.TL_updatePrivacy) { if (update.key instanceof TLRPC.TL_privacyKeyStatusTimestamp) { - ContactsController.getInstance().setPrivacyRules(update.rules); + ContactsController.getInstance().setPrivacyRules(update.rules, false); + } else if (update.key instanceof TLRPC.TL_privacyKeyChatInvite) { + ContactsController.getInstance().setPrivacyRules(update.rules, true); } } else if (update instanceof TLRPC.TL_updateUserStatus) { if (update.status instanceof TLRPC.TL_userStatusRecently) { @@ -5661,6 +5965,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (dialog != null) { dialog.notify_settings = update.notify_settings; } + editor.putBoolean("silent_" + dialog_id, update.notify_settings.silent); if (update.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime()) { int until = 0; if (update.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { @@ -5724,16 +6029,63 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!webPages.isEmpty()) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceivedWebpagesInUpdates, webPages); + for (HashMap.Entry entry : webPages.entrySet()) { + ArrayList arrayList = reloadingWebpagesPending.remove(entry.getKey()); + if (arrayList != null) { + TLRPC.WebPage webpage = entry.getValue(); + ArrayList messagesArr = new ArrayList<>(); + long dialog_id = 0; + if (webpage instanceof TLRPC.TL_webPage || webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = webpage; + if (a == 0) { + dialog_id = arrayList.get(a).getDialogId(); + ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); + } + messagesArr.add(arrayList.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(webpage.id, arrayList); + } + if (!messagesArr.isEmpty()) { + MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + } } + boolean updateDialogs = false; + if (!editingMessages.isEmpty()) { + for (HashMap.Entry> pair : editingMessages.entrySet()) { + Long dialog_id = pair.getKey(); + ArrayList arrayList = pair.getValue(); + MessageObject oldObject = dialogMessage.get(dialog_id); + if (oldObject != null) { + for (int a = 0; a < arrayList.size(); a++) { + MessageObject newMessage = arrayList.get(a); + if (oldObject.getId() == newMessage.getId()) { + dialogMessage.put(dialog_id, newMessage); + updateDialogs = true; + break; + } + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } if (!messages.isEmpty()) { for (HashMap.Entry> entry : messages.entrySet()) { Long key = entry.getKey(); ArrayList value = entry.getValue(); updateInterfaceWithMessages(key, value); } + updateDialogs = true; + } + if (updateDialogs) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); } + if (printChangedArg) { updateMask |= UPDATE_MASK_USER_PRINT; } @@ -5742,7 +6094,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter updateMask |= UPDATE_MASK_USER_PHONE; } if (!chatInfoToUpdate.isEmpty()) { - for (TLRPC.ChatParticipants info : chatInfoToUpdate) { + for (int a = 0; a < chatInfoToUpdate.size(); a++) { + TLRPC.ChatParticipants info = chatInfoToUpdate.get(a); MessagesStorage.getInstance().updateChatParticipants(info); } } @@ -5866,7 +6219,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } if (!tasks.isEmpty()) { - for (TLRPC.TL_updateEncryptedMessagesRead update : tasks) { + for (int a = 0; a < tasks.size(); a++) { + TLRPC.TL_updateEncryptedMessagesRead update = tasks.get(a); MessagesStorage.getInstance().createTaskForSecretChat(update.chat_id, update.max_date, update.date, 1, null); } } @@ -5962,7 +6316,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter channelId = message.messageOwner.to_id.channel_id; } } - if (message.isOut() && message.isNewGif() && !message.isSending()) { + if (message.isOut() && message.isNewGif() && !message.isSending() && !message.isForwarded()) { addNewGifToRecent(message.messageOwner.media.document, message.messageOwner.date); } } @@ -5982,7 +6336,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogs_read_inbox_max.remove(dialog.id); nextDialogsCacheOffset--; dialogMessage.remove(dialog.id); - dialogMessagesByIds.remove(dialog.top_message); + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } dialog.top_message = 0; NotificationsController.getInstance().removeNotificationsForDialog(dialog.id); NotificationCenter.getInstance().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); @@ -6012,6 +6369,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(uid, lastMessage); if (lastMessage.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(lastMessage.getId(), lastMessage); + if (lastMessage.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage); + } } nextDialogsCacheOffset++; changed = true; @@ -6020,6 +6380,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter if ((dialog.top_message > 0 && lastMessage.getId() > 0 && lastMessage.getId() > dialog.top_message) || (dialog.top_message < 0 && lastMessage.getId() < 0 && lastMessage.getId() < dialog.top_message) || !dialogMessage.containsKey(uid) || dialog.top_message < 0 || dialog.last_message_date <= lastMessage.messageOwner.date) { + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } dialog.top_message = lastMessage.getId(); if (!isBroadcast) { dialog.last_message_date = lastMessage.messageOwner.date; @@ -6028,6 +6392,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialogMessage.put(uid, lastMessage); if (lastMessage.messageOwner.to_id.channel_id == 0) { dialogMessagesByIds.put(lastMessage.getId(), lastMessage); + if (lastMessage.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index a904bd732..15079dbb0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -22,7 +22,6 @@ import org.telegram.messenger.query.BotQuery; import org.telegram.messenger.query.SharedMediaQuery; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; -import org.telegram.tgnet.TLClassStore; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; @@ -166,7 +165,7 @@ public class MessagesStorage { database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); //version - database.executeFast("PRAGMA user_version = 29").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 30").stepThis().dispose(); //database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose(); //database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); @@ -200,7 +199,7 @@ public class MessagesStorage { } } int version = database.executeInt("PRAGMA user_version"); - if (version < 29) { + if (version < 30) { updateDbToLastVersion(version); } } @@ -464,11 +463,6 @@ public class MessagesStorage { database.executeFast("PRAGMA user_version = 23").stepThis().dispose(); version = 23; } - if (version == 23) { - database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); - database.executeFast("PRAGMA user_version = 24").stepThis().dispose(); - version = 24; - } if (version == 24) { database.executeFast("DELETE FROM media_holes_v2 WHERE uid != 0 AND type >= 0 AND start IN (0, 1)").stepThis().dispose(); database.executeFast("PRAGMA user_version = 25").stepThis().dispose(); @@ -487,7 +481,13 @@ public class MessagesStorage { if (version == 28) { database.executeFast("CREATE TABLE IF NOT EXISTS bot_recent(id INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); database.executeFast("PRAGMA user_version = 29").stepThis().dispose(); - //version = 29; + version = 29; + } + if (version == 29) { + database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); + database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 30").stepThis().dispose(); + //version = 30; } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1028,27 +1028,13 @@ public class MessagesStorage { if (message == null || message.media == null) { continue; } - if (message.media instanceof TLRPC.TL_messageMediaAudio) { - File file = FileLoader.getPathToAttach(message.media.audio); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { File file = FileLoader.getPathToAttach(photoSize); if (file != null && file.toString().length() > 0) { filesToDelete.add(file); } } - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { - File file = FileLoader.getPathToAttach(message.media.video); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - file = FileLoader.getPathToAttach(message.media.video.thumb); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { File file = FileLoader.getPathToAttach(message.media.document); if (file != null && file.toString().length() > 0) { @@ -1287,6 +1273,7 @@ public class MessagesStorage { try { int minDate = Integer.MAX_VALUE; SparseArray> messages = new SparseArray<>(); + final ArrayList midsArray = new ArrayList<>(); StringBuilder mids = new StringBuilder(); SQLiteCursor cursor; if (random_ids == null) { @@ -1297,10 +1284,13 @@ public class MessagesStorage { } while (cursor.next()) { int ttl = cursor.intValue(1); + int mid = cursor.intValue(0); + if (random_ids != null) { + midsArray.add((long) mid); + } if (ttl <= 0) { continue; } - int mid = cursor.intValue(0); int date = Math.min(readTime, time) + ttl; minDate = Math.min(minDate, date); ArrayList arr = messages.get(date); @@ -1315,15 +1305,26 @@ public class MessagesStorage { arr.add(mid); } cursor.dispose(); + + if (random_ids != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesStorage.getInstance().markMessagesContentAsRead(midsArray); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, midsArray); + } + }); + } + if (messages.size() != 0) { database.beginTransaction(); SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); for (int a = 0; a < messages.size(); a++) { int key = messages.keyAt(a); ArrayList arr = messages.get(key); - for (Integer mid : arr) { + for (int b = 0; b < arr.size(); b++) { state.requery(); - state.bindInteger(1, mid); + state.bindInteger(1, arr.get(b)); state.bindInteger(2, key); state.step(); } @@ -2116,6 +2117,36 @@ public class MessagesStorage { }); } + public boolean checkMessageId(final long dialog_id, final int mid) { + final boolean[] result = new boolean[1]; + final Semaphore semaphore = new Semaphore(0); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d AND mid = %d", dialog_id, mid)); + if (cursor.next()) { + result[0] = true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return result[0]; + } + public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final int load_type, final int important, final int loadIndex) { storageQueue.postRunnable(new Runnable() { @Override @@ -2143,6 +2174,7 @@ public class MessagesStorage { ArrayList chatsToLoad = new ArrayList<>(); ArrayList replyMessages = new ArrayList<>(); HashMap> replyMessageOwners = new HashMap<>(); + HashMap> replyMessageRandomOwners = new HashMap<>(); SQLiteCursor cursor; int lower_id = (int) dialog_id; @@ -2389,7 +2421,7 @@ public class MessagesStorage { addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - if (message.reply_to_msg_id != 0) { + if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) { boolean ok = false; if (!cursor.isNull(6)) { NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(6)); @@ -2403,19 +2435,31 @@ public class MessagesStorage { data2.reuse(); } if (!ok) { - long messageId = message.reply_to_msg_id; - if (message.to_id.channel_id != 0) { - messageId |= ((long) message.to_id.channel_id) << 32; + if (message.reply_to_msg_id != 0) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + ArrayList messages = replyMessageOwners.get(message.reply_to_msg_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageOwners.put(message.reply_to_msg_id, messages); + } + messages.add(message); + } else { + if (!replyMessages.contains(message.reply_to_random_id)) { + replyMessages.add(message.reply_to_random_id); + } + ArrayList messages = replyMessageRandomOwners.get(message.reply_to_random_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageRandomOwners.put(message.reply_to_random_id, messages); + } + messages.add(message); } - if (!replyMessages.contains(messageId)) { - replyMessages.add(messageId); - } - ArrayList messages = replyMessageOwners.get(message.reply_to_msg_id); - if (messages == null) { - messages = new ArrayList<>(); - replyMessageOwners.put(message.reply_to_msg_id, messages); - } - messages.add(message); } } message.send_state = cursor.intValue(2); @@ -2499,7 +2543,11 @@ public class MessagesStorage { } if (!replyMessages.isEmpty()) { - cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + if (!replyMessageOwners.isEmpty()) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); + } while (cursor.next()) { NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data) != 0) { @@ -2510,16 +2558,35 @@ public class MessagesStorage { addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - ArrayList arrayList = replyMessageOwners.get(message.id); - if (arrayList != null) { - for (TLRPC.Message m : arrayList) { - m.replyMessage = message; + if (!replyMessageOwners.isEmpty()) { + ArrayList arrayList = replyMessageOwners.get(message.id); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).replyMessage = message; + } + } + } else { + ArrayList arrayList = replyMessageRandomOwners.remove(cursor.longValue(3)); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message object = arrayList.get(a); + object.replyMessage = message; + object.reply_to_msg_id = message.id; + } } } } data.reuse(); } cursor.dispose(); + if (!replyMessageRandomOwners.isEmpty()) { + for (HashMap.Entry> entry : replyMessageRandomOwners.entrySet()) { + ArrayList arrayList = entry.getValue(); + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).reply_to_random_id = 0; + } + } + } } if (!usersToLoad.isEmpty()) { @@ -2599,9 +2666,11 @@ public class MessagesStorage { if (cursor.next()) { NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); if (data != null && cursor.byteBufferValue(0, data) != 0) { - TLObject file = TLClassStore.Instance().TLdeserialize(data, data.readInt32(false), false); - if (file != null) { - result.add(file); + TLObject file = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + if (file instanceof TLRPC.TL_messageMediaDocument) { + result.add(((TLRPC.TL_messageMediaDocument) file).document); + } else if (file instanceof TLRPC.TL_messageMediaPhoto) { + result.add(((TLRPC.TL_messageMediaDocument) file).photo); } } data.reuse(); @@ -2634,10 +2703,23 @@ public class MessagesStorage { try { String id = Utilities.MD5(path); if (id != null) { + TLRPC.MessageMedia messageMedia = null; + if (file instanceof TLRPC.Photo) { + messageMedia = new TLRPC.TL_messageMediaPhoto(); + messageMedia.caption = ""; + messageMedia.photo = (TLRPC.Photo) file; + } else if (file instanceof TLRPC.Document) { + messageMedia = new TLRPC.TL_messageMediaDocument(); + messageMedia.caption = ""; + messageMedia.document = (TLRPC.Document) file; + } + if (messageMedia == null) { + return; + } state = database.executeFast("REPLACE INTO sent_files_v2 VALUES(?, ?, ?)"); state.requery(); - NativeByteBuffer data = new NativeByteBuffer(file.getObjectSize()); - file.serializeToStream(data); + NativeByteBuffer data = new NativeByteBuffer(messageMedia.getObjectSize()); + messageMedia.serializeToStream(data); state.bindString(1, id); state.bindInteger(2, type); state.bindByteBuffer(3, data); @@ -2738,10 +2820,8 @@ public class MessagesStorage { public void run() { SQLitePreparedStatement state = null; try { - if ((chat.key_hash == null || chat.key_hash.length != 16) && chat.auth_key != null) { - byte[] sha1 = Utilities.computeSHA1(chat.auth_key); - chat.key_hash = new byte[16]; - System.arraycopy(sha1, 0, chat.key_hash, 0, chat.key_hash.length); + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); } state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ?, use_count = ?, exchange_id = ?, key_date = ?, fprint = ?, fauthkey = ?, khash = ? WHERE uid = ?"); @@ -2856,10 +2936,8 @@ public class MessagesStorage { @Override public void run() { try { - if ((chat.key_hash == null || chat.key_hash.length != 16) && chat.auth_key != null) { - byte[] sha1 = Utilities.computeSHA1(chat.auth_key); - chat.key_hash = new byte[16]; - System.arraycopy(sha1, 0, chat.key_hash, 0, chat.key_hash.length); + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); } SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); @@ -2950,7 +3028,46 @@ public class MessagesStorage { return; } SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); - for (TLRPC.User user : users) { + for (int a = 0; a < users.size(); a++) { + TLRPC.User user = users.get(a); + if (user.min) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM users WHERE uid = %d", user.id)); + if (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.User oldUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + if (user != null) { + if (user.first_name != null) { + oldUser.first_name = user.first_name; + oldUser.flags |= 2; + } else { + oldUser.first_name = null; + oldUser.flags = oldUser.flags &~ 2; + } + if (user.last_name != null) { + oldUser.last_name = user.last_name; + oldUser.flags |= 4; + } else { + oldUser.last_name = null; + oldUser.flags = oldUser.flags &~ 4; + } + if (user.photo != null) { + oldUser.photo = user.photo; + oldUser.flags |= 32; + } else { + oldUser.photo = null; + oldUser.flags = oldUser.flags &~ 32; + } + } + user = oldUser; + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } state.requery(); NativeByteBuffer data = new NativeByteBuffer(user.getObjectSize()); user.serializeToStream(data); @@ -2980,7 +3097,8 @@ public class MessagesStorage { return; } SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); - for (TLRPC.Chat chat : chats) { + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); state.requery(); NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); chat.serializeToStream(data); @@ -3171,7 +3289,12 @@ public class MessagesStorage { downloadObject.id = cursor.longValue(0); NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(2)); if (data != null && cursor.byteBufferValue(2, data) != 0) { - downloadObject.object = TLClassStore.Instance().TLdeserialize(data, data.readInt32(false), false); + TLRPC.MessageMedia messageMedia = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + if (messageMedia.document != null) { + downloadObject.object = messageMedia.document; + } else if (messageMedia.photo != null) { + downloadObject.object = FileLoader.getClosestPhotoSizeWithSize(messageMedia.photo.sizes, AndroidUtilities.getPhotoSize()); + } } data.reuse(); objects.add(downloadObject); @@ -3194,10 +3317,10 @@ public class MessagesStorage { private int getMessageMediaType(TLRPC.Message message) { if (message instanceof TLRPC.TL_message_secret && ( message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl > 0 && message.ttl <= 60 || - message.media instanceof TLRPC.TL_messageMediaAudio || - message.media instanceof TLRPC.TL_messageMediaVideo)) { + MessageObject.isVoiceMessage(message) || + MessageObject.isVideoMessage(message))) { return 1; - } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) { return 0; } return -1; @@ -3611,15 +3734,17 @@ public class MessagesStorage { data.reuse(); if ((message.to_id.channel_id == 0 || MessageObject.isImportant(message)) && message.date >= ConnectionsManager.getInstance().getCurrentTime() - 60 * 60 && downloadMask != 0) { - if (message.media instanceof TLRPC.TL_messageMediaAudio || message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaDocument) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaDocument) { int type = 0; long id = 0; - TLObject object = null; - if (message.media instanceof TLRPC.TL_messageMediaAudio) { - if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_AUDIO) != 0 && message.media.audio.size < 1024 * 1024 * 5) { - id = message.media.audio.id; + TLRPC.MessageMedia object = null; + if (MessageObject.isVoiceMessage(message)) { + if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_AUDIO) != 0 && message.media.document.size < 1024 * 1024 * 5) { + id = message.media.document.id; type = MediaController.AUTODOWNLOAD_MASK_AUDIO; - object = message.media.audio; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; } } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_PHOTO) != 0) { @@ -3627,20 +3752,26 @@ public class MessagesStorage { if (photoSize != null) { id = message.media.photo.id; type = MediaController.AUTODOWNLOAD_MASK_PHOTO; - object = photoSize; + object = new TLRPC.TL_messageMediaPhoto(); + object.caption = ""; + object.photo = message.media.photo; } } - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (MessageObject.isVideoMessage(message)) { if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_VIDEO) != 0) { - id = message.media.video.id; + id = message.media.document.id; type = MediaController.AUTODOWNLOAD_MASK_VIDEO; - object = message.media.video; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; } } else if (message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isMusicMessage(message) && !MessageObject.isGifDocument(message.media.document)) { if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_DOCUMENT) != 0) { id = message.media.document.id; type = MediaController.AUTODOWNLOAD_MASK_DOCUMENT; - object = message.media.document; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; } } if (object != null) { @@ -4260,27 +4391,13 @@ public class MessagesStorage { if (message == null || message.media == null) { continue; } - if (message.media instanceof TLRPC.TL_messageMediaAudio) { - File file = FileLoader.getPathToAttach(message.media.audio); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { File file = FileLoader.getPathToAttach(photoSize); if (file != null && file.toString().length() > 0) { filesToDelete.add(file); } } - } else if (message.media instanceof TLRPC.TL_messageMediaVideo) { - File file = FileLoader.getPathToAttach(message.media.video); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } - file = FileLoader.getPathToAttach(message.media.video.thumb); - if (file != null && file.toString().length() > 0) { - filesToDelete.add(file); - } } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { File file = FileLoader.getPathToAttach(message.media.document); if (file != null && file.toString().length() > 0) { @@ -4792,6 +4909,15 @@ public class MessagesStorage { messageId |= ((long) channelId) << 32; } + if (load_type == -2) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE mid = %d", messageId)); + boolean exist = cursor.next(); + cursor.dispose(); + if (!exist) { + continue; + } + } + if (a == 0 && createDialog) { SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); state3.bindLong(1, dialog_id); @@ -4801,7 +4927,7 @@ public class MessagesStorage { state3.bindInteger(5, message.id); state3.bindInteger(6, 0); state3.bindLong(7, messageId); - state3.bindInteger(8, 0); + state3.bindInteger(8, load_type < 0 ? message.ttl : 0); state3.bindInteger(9, messages.pts); state3.bindInteger(10, message.date); state3.step(); @@ -4809,7 +4935,7 @@ public class MessagesStorage { } boolean isImportant = MessageObject.isImportant(message); - if (load_type != -1 && important == 1) { + if (load_type >= 0 && important == 1) { if (isImportant) { minChannelMessageId = Math.min(minChannelMessageId, message.id); maxChannelMessageId = Math.max(maxChannelMessageId, message.id); @@ -4874,7 +5000,7 @@ public class MessagesStorage { BotQuery.putBotKeyboard(dialog_id, botKeyboard); } - if (load_type != -1 && important != 0) { + if (load_type >= 0 && important != 0) { /*if ((messages.flags & 1) == 0) { if (countBeforeImportant != 0) { if (load_type == 0) { @@ -4979,17 +5105,17 @@ public class MessagesStorage { if (message.media.user_id != 0 && !usersToLoad.contains(message.media.user_id)) { usersToLoad.add(message.media.user_id); } - if (message.media.audio != null && message.media.audio.user_id != 0 && !usersToLoad.contains(message.media.audio.user_id)) { - usersToLoad.add(message.media.audio.user_id); - } } - if (message.fwd_from_id instanceof TLRPC.TL_peerUser) { - if (!usersToLoad.contains(message.fwd_from_id.user_id)) { - usersToLoad.add(message.fwd_from_id.user_id); + if (message.fwd_from != null) { + if (message.fwd_from.from_id != 0) { + if (!usersToLoad.contains(message.fwd_from.from_id)) { + usersToLoad.add(message.fwd_from.from_id); + } } - } else if (message.fwd_from_id instanceof TLRPC.TL_peerChannel) { - if (!chatsToLoad.contains(message.fwd_from_id.channel_id)) { - chatsToLoad.add(message.fwd_from_id.channel_id); + if (message.fwd_from.channel_id != 0) { + if (!chatsToLoad.contains(message.fwd_from.channel_id)) { + chatsToLoad.add(message.fwd_from.channel_id); + } } } if (message.ttl < 0) { @@ -5010,7 +5136,7 @@ public class MessagesStorage { usersToLoad.add(UserConfig.getClientUserId()); ArrayList chatsToLoad = new ArrayList<>(); ArrayList encryptedToLoad = new ArrayList<>(); - SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.date DESC LIMIT %d,%d", offset, count)); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max, d.date_i FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.date DESC LIMIT %d,%d", offset, count)); while (cursor.next()) { TLRPC.Dialog dialog; int pts = cursor.intValue(12); @@ -5026,6 +5152,7 @@ public class MessagesStorage { dialog.last_message_date = cursor.intValue(3); dialog.pts = pts; dialog.read_inbox_max_id = cursor.intValue(13); + dialog.last_message_date_i = cursor.intValue(14); dialog.top_not_important_message = cursor.intValue(10); dialog.unread_not_important_count = cursor.intValue(11); long flags = cursor.longValue(8); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java index f5fe15f88..e1bbf9513 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java @@ -21,15 +21,13 @@ import android.media.RemoteControlClient; import android.os.Build; import android.os.IBinder; import android.support.v4.app.NotificationCompat; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; import android.view.View; import android.widget.RemoteViews; import org.telegram.messenger.audioinfo.AudioInfo; import org.telegram.ui.LaunchActivity; -public class MusicPlayerService extends Service implements AudioManager.OnAudioFocusChangeListener, NotificationCenter.NotificationCenterDelegate { +public class MusicPlayerService extends Service implements NotificationCenter.NotificationCenterDelegate { public static final String NOTIFY_PREVIOUS = "org.telegram.android.musicplayer.previous"; public static final String NOTIFY_CLOSE = "org.telegram.android.musicplayer.close"; @@ -39,8 +37,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF private RemoteControlClient remoteControlClient; private AudioManager audioManager; - private static boolean ignoreAudioFocus = false; - private PhoneStateListener phoneStateListener; private static boolean supportBigNotifications = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; private static boolean supportLockScreenControls = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; @@ -55,29 +51,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged); NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged); - try { - phoneStateListener = new PhoneStateListener() { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - if (state == TelephonyManager.CALL_STATE_RINGING) { - if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { - MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); - } - } else if (state == TelephonyManager.CALL_STATE_IDLE) { - - } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) { - - } - super.onCallStateChanged(state, incomingNumber); - } - }; - TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); - if (mgr != null) { - mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } super.onCreate(); } @@ -220,7 +193,6 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover()); } metadataEditor.apply(); - audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); } } @@ -246,35 +218,11 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF metadataEditor.clear(); metadataEditor.apply(); audioManager.unregisterRemoteControlClient(remoteControlClient); - audioManager.abandonAudioFocus(this); - } - try { - TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); - if (mgr != null) { - mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); - } - } catch (Exception e) { - FileLog.e("tmessages", e); } NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged); } - @Override - public void onAudioFocusChange(int focusChange) { - if (ignoreAudioFocus) { - ignoreAudioFocus = false; - return; - } - if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { - if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { - MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); - } - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - //MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); - } - } - @Override public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.audioPlayStateChanged) { @@ -286,8 +234,4 @@ public class MusicPlayerService extends Service implements AudioManager.OnAudioF } } } - - public static void setIgnoreAudioFocus() { - ignoreAudioFocus = true; - } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java index dc9c57316..46251dfbd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -23,7 +23,7 @@ import java.util.zip.ZipFile; public class NativeLoader { - private final static int LIB_VERSION = 17; + private final static int LIB_VERSION = 19; private final static String LIB_NAME = "tmessages." + LIB_VERSION; private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java index c01709277..6fd1db240 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -77,6 +77,7 @@ public class NotificationCenter { public static final int closeOtherAppActivities = totalEvents++; public static final int didUpdatedConnectionState = totalEvents++; public static final int didReceiveSmsCode = totalEvents++; + public static final int didReceiveCall = totalEvents++; public static final int emojiDidLoaded = totalEvents++; public static final int appDidLogout = totalEvents++; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index fc10b9360..5276b742f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -78,8 +78,10 @@ public class NotificationsController { private SoundPool soundPool; private int soundIn; private int soundOut; + private int soundRecord; private boolean soundInLoaded; private boolean soundOutLoaded; + private boolean soundRecordLoaded; protected AudioManager audioManager; private AlarmManager alarmManager; @@ -681,7 +683,11 @@ public class NotificationsController { int chat_id = messageObject.messageOwner.to_id.chat_id != 0 ? messageObject.messageOwner.to_id.chat_id : messageObject.messageOwner.to_id.channel_id; int from_id = messageObject.messageOwner.to_id.user_id; if (from_id == 0) { - from_id = messageObject.messageOwner.from_id; + if (messageObject.isFromUser()) { + from_id = messageObject.messageOwner.from_id; + } else { + from_id = -chat_id; + } } else if (from_id == UserConfig.getClientUserId()) { from_id = messageObject.messageOwner.from_id; } @@ -747,8 +753,10 @@ public class NotificationsController { } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { msg = LocaleController.formatString("NotificationMessagePhoto", R.string.NotificationMessagePhoto, name); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (messageObject.isVideo()) { msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, name); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, name); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { @@ -761,8 +769,6 @@ public class NotificationsController { } else { msg = LocaleController.formatString("NotificationMessageDocument", R.string.NotificationMessageDocument, name); } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name); } } } else { @@ -857,8 +863,10 @@ public class NotificationsController { } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { msg = LocaleController.formatString("ChannelMessagePhoto", R.string.ChannelMessagePhoto, name, chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (messageObject.isVideo()) { msg = LocaleController.formatString("ChannelMessageVideo", R.string.ChannelMessageVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { msg = LocaleController.formatString("ChannelMessageContact", R.string.ChannelMessageContact, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { @@ -871,8 +879,6 @@ public class NotificationsController { } else { msg = LocaleController.formatString("ChannelMessageDocument", R.string.ChannelMessageDocument, name, chat.title); } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name, chat.title); } } else { if (messageObject.isMediaEmpty()) { @@ -883,8 +889,10 @@ public class NotificationsController { } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { msg = LocaleController.formatString("ChannelMessageGroupPhoto", R.string.ChannelMessageGroupPhoto, name, chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (messageObject.isVideo()) { msg = LocaleController.formatString("ChannelMessageGroupVideo", R.string.ChannelMessageGroupVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { msg = LocaleController.formatString("ChannelMessageGroupContact", R.string.ChannelMessageGroupContact, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { @@ -897,8 +905,6 @@ public class NotificationsController { } else { msg = LocaleController.formatString("ChannelMessageGroupDocument", R.string.ChannelMessageGroupDocument, name, chat.title); } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title); } } } else { @@ -910,8 +916,10 @@ public class NotificationsController { } } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { msg = LocaleController.formatString("NotificationMessageGroupPhoto", R.string.NotificationMessageGroupPhoto, name, chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + } else if (messageObject.isVideo()) { msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, name, chat.title); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { @@ -924,13 +932,15 @@ public class NotificationsController { } else { msg = LocaleController.formatString("NotificationMessageGroupDocument", R.string.NotificationMessageGroupDocument, name, chat.title); } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title); } } } } else { - msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, name, chat.title); + if (ChatObject.isChannel(chat) && !chat.megagroup) { + msg = LocaleController.formatString("ChannelMessageNoText", R.string.ChannelMessageNoText, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, name, chat.title); + } } } } @@ -1012,8 +1022,45 @@ public class NotificationsController { } } + /*public void playRecordSound() { + try { + if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + return; + } + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + if (status == 0) { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } + } + }); + } + if (soundRecord == 0 && !soundRecordLoaded) { + soundRecordLoaded = true; + soundRecord = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_record, 1); + } + if (soundRecord != 0) { + soundPool.play(soundRecord, 1.0f, 1.0f, 1, 0, 1.0f); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + }*/ + private void playInChatSound() { - if (!inChatSoundEnabled) { + if (!inChatSoundEnabled || MediaController.getInstance().isRecordingAudio()) { return; } try { @@ -1038,7 +1085,7 @@ public class NotificationsController { } try { if (soundPool == null) { - soundPool = new SoundPool(2, AudioManager.STREAM_SYSTEM, 0); + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { @Override public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { @@ -1298,26 +1345,17 @@ public class NotificationsController { .setGroupSummary(true) .setColor(0xff2ca5e0); - if (!notifyAboutLast) { - mBuilder.setPriority(NotificationCompat.PRIORITY_LOW); - } else { - if (priority == 0) { - mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT); - } else if (priority == 1) { - mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH); - } else if (priority == 2) { - mBuilder.setPriority(NotificationCompat.PRIORITY_MAX); - } - } - mBuilder.setCategory(NotificationCompat.CATEGORY_MESSAGE); if (chat == null && user != null && user.phone != null && user.phone.length() > 0) { mBuilder.addPerson("tel:+" + user.phone); } + int silent = 2; String lastMessage = null; if (pushMessages.size() == 1) { - String message = lastMessage = getStringForMessage(pushMessages.get(0), false); + MessageObject messageObject = pushMessages.get(0); + String message = lastMessage = getStringForMessage(messageObject, false); + silent = messageObject.messageOwner.silent ? 1 : 0; if (message == null) { return; } @@ -1336,12 +1374,14 @@ public class NotificationsController { inboxStyle.setBigContentTitle(name); int count = Math.min(10, pushMessages.size()); for (int i = 0; i < count; i++) { - String message = getStringForMessage(pushMessages.get(i), false); + MessageObject messageObject = pushMessages.get(i); + String message = getStringForMessage(messageObject, false); if (message == null) { continue; } - if (i == 0) { + if (silent == 2) { lastMessage = message; + silent = messageObject.messageOwner.silent ? 1 : 0; } if (pushDialogs.size() == 1) { if (replace) { @@ -1365,29 +1405,44 @@ public class NotificationsController { } } - if (!notifyDisabled) { + if (silent == 1) { + FileLog.e("tmessages", "don't notify " + lastMessage); + } else { + FileLog.e("tmessages", "notify" + lastMessage); + } + + if (!notifyAboutLast || silent == 1) { + mBuilder.setPriority(NotificationCompat.PRIORITY_LOW); + } else { + if (priority == 0) { + mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT); + } else if (priority == 1) { + mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH); + } else if (priority == 2) { + mBuilder.setPriority(NotificationCompat.PRIORITY_MAX); + } + } + + if (silent != 1 && !notifyDisabled) { if (ApplicationLoader.mainInterfacePaused || inAppPreview) { if (lastMessage.length() > 100) { lastMessage = lastMessage.substring(0, 100).replace("\n", " ").trim() + "..."; } mBuilder.setTicker(lastMessage); } - if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) { - if (choosenSoundPath.equals(defaultPath)) { - /*MediaPlayer mediaPlayer = new MediaPlayer(); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); - mediaPlayer.setDataSource(ApplicationLoader.applicationContext, Settings.System.DEFAULT_NOTIFICATION_URI); - mediaPlayer.prepare(); - mediaPlayer.start();*/ - mBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, AudioManager.STREAM_NOTIFICATION); - } else { - mBuilder.setSound(Uri.parse(choosenSoundPath), AudioManager.STREAM_NOTIFICATION); + if (!MediaController.getInstance().isRecordingAudio()) { + if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) { + if (choosenSoundPath.equals(defaultPath)) { + mBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, AudioManager.STREAM_NOTIFICATION); + } else { + mBuilder.setSound(Uri.parse(choosenSoundPath), AudioManager.STREAM_NOTIFICATION); + } } } if (ledColor != 0) { mBuilder.setLights(ledColor, 1000, 1000); } - if (needVibrate == 2) { + if (needVibrate == 2 || MediaController.getInstance().isRecordingAudio()) { mBuilder.setVibrate(new long[]{0, 0}); } else if (needVibrate == 1) { mBuilder.setVibrate(new long[]{0, 100, 0, 100}); @@ -1597,7 +1652,7 @@ public class NotificationsController { } public void playOutChatSound() { - if (!inChatSoundEnabled) { + if (!inChatSoundEnabled || MediaController.getInstance().isRecordingAudio()) { return; } try { @@ -1616,7 +1671,7 @@ public class NotificationsController { } lastSoundOutPlay = System.currentTimeMillis(); if (soundPool == null) { - soundPool = new SoundPool(2, AudioManager.STREAM_SYSTEM, 0); + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { @Override public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { @@ -1642,14 +1697,13 @@ public class NotificationsController { public static void updateServerNotificationsSettings(long dialog_id) { NotificationCenter.getInstance().postNotificationName(NotificationCenter.notificationsSettingsUpdated); - if ((int)dialog_id == 0) { + if ((int) dialog_id == 0) { return; } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); req.settings = new TLRPC.TL_inputPeerNotifySettings(); req.settings.sound = "default"; - req.settings.events_mask = 0; int mute_type = preferences.getInt("notify2_" + dialog_id, 0); if (mute_type == 3) { req.settings.mute_until = preferences.getInt("notifyuntil_" + dialog_id, 0); @@ -1657,14 +1711,9 @@ public class NotificationsController { req.settings.mute_until = mute_type != 2 ? 0 : Integer.MAX_VALUE; } req.settings.show_previews = preferences.getBoolean("preview_" + dialog_id, true); - + req.settings.silent = preferences.getBoolean("silent_" + dialog_id, false); req.peer = new TLRPC.TL_inputNotifyPeer(); - - ((TLRPC.TL_inputNotifyPeer)req.peer).peer = MessagesController.getInputPeer((int) dialog_id); - if (((TLRPC.TL_inputNotifyPeer)req.peer).peer == null) { - return; - } - + ((TLRPC.TL_inputNotifyPeer) req.peer).peer = MessagesController.getInputPeer((int) dialog_id); ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java index b1356568c..8878ebaaa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -14,6 +14,7 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; +import org.telegram.tgnet.AbstractSerializedData; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.NativeByteBuffer; import org.telegram.tgnet.RequestDelegate; @@ -31,10 +32,42 @@ import java.util.concurrent.ConcurrentHashMap; public class SecretChatHelper { - public static final int CURRENT_SECRET_CHAT_LAYER = 23; + public static class TL_decryptedMessageHolder extends TLObject { + public static int constructor = 0x555555F9; + + public long random_id; + public int date; + public TLRPC.TL_decryptedMessageLayer layer; + public TLRPC.EncryptedFile file; + public boolean new_key_used; + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + date = stream.readInt32(exception); + layer = TLRPC.TL_decryptedMessageLayer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (stream.readBool(exception)) { + file = TLRPC.EncryptedFile.TLdeserialize(stream, stream.readInt32(exception), exception); + } + new_key_used = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(date); + layer.serializeToStream(stream); + stream.writeBool(file != null); + if (file != null) { + file.serializeToStream(stream); + } + stream.writeBool(new_key_used); + } + } + + public static final int CURRENT_SECRET_CHAT_LAYER = 46; private ArrayList sendingNotifyLayer = new ArrayList<>(); - private HashMap> secretHolesQueue = new HashMap<>(); + private HashMap> secretHolesQueue = new HashMap<>(); private HashMap acceptingChats = new HashMap<>(); public ArrayList delayedEncryptedChatUpdates = new ArrayList<>(); private ArrayList pendingEncMessagesToDelete = new ArrayList<>(); @@ -67,6 +100,18 @@ public class SecretChatHelper { protected void processPendingEncMessages() { if (!pendingEncMessagesToDelete.isEmpty()) { + final ArrayList pendingEncMessagesToDeleteCopy = new ArrayList<>(pendingEncMessagesToDelete); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (int a = 0; a < pendingEncMessagesToDeleteCopy.size(); a++) { + MessageObject messageObject = MessagesController.getInstance().dialogMessagesByRandomIds.get(pendingEncMessagesToDeleteCopy.get(a)); + if (messageObject != null) { + messageObject.deleted = true; + } + } + } + }); ArrayList arr = new ArrayList<>(pendingEncMessagesToDelete); MessagesStorage.getInstance().markMessagesAsDeletedByRandoms(arr); pendingEncMessagesToDelete.clear(); @@ -114,7 +159,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -219,7 +264,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -247,7 +292,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -278,7 +323,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -307,7 +352,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -338,7 +383,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -370,7 +415,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -401,7 +446,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -431,7 +476,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -459,7 +504,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -495,7 +540,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { reqSend = new TLRPC.TL_decryptedMessageService(); } else { - reqSend = new TLRPC.TL_decryptedMessageService_old(); + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } @@ -544,37 +589,6 @@ public class SecretChatHelper { MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.photo, 3); - } else if (newMsg.media instanceof TLRPC.TL_messageMediaVideo && newMsg.media.video != null) { - TLRPC.Video video = newMsg.media.video; - newMsg.media.video = new TLRPC.TL_videoEncrypted(); - newMsg.media.video.duration = video.duration; - newMsg.media.video.thumb = video.thumb; - newMsg.media.video.dc_id = file.dc_id; - newMsg.media.video.w = video.w; - newMsg.media.video.h = video.h; - newMsg.media.video.date = video.date; - newMsg.media.caption = video.caption != null ? video.caption : ""; - newMsg.media.video.size = file.size; - newMsg.media.video.id = file.id; - newMsg.media.video.access_hash = file.access_hash; - newMsg.media.video.key = decryptedMessage.media.key; - newMsg.media.video.iv = decryptedMessage.media.iv; - newMsg.media.video.mime_type = video.mime_type; - newMsg.media.video.caption = video.caption != null ? video.caption : ""; - - if (newMsg.attachPath != null && newMsg.attachPath.startsWith(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE).getAbsolutePath())) { - File cacheFile = new File(newMsg.attachPath); - File cacheFile2 = FileLoader.getPathToAttach(newMsg.media.video); - if (cacheFile.renameTo(cacheFile2)) { - newMsg.attachPath = ""; - } - } - - ArrayList arr = new ArrayList<>(); - arr.add(newMsg); - MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); - - //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.video, 5); } else if (newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { TLRPC.Document document = newMsg.media.document; newMsg.media.document = new TLRPC.TL_documentEncrypted(); @@ -588,6 +602,7 @@ public class SecretChatHelper { newMsg.media.document.iv = decryptedMessage.media.iv; newMsg.media.document.thumb = document.thumb; newMsg.media.document.dc_id = file.dc_id; + newMsg.media.document.caption = document.caption != null ? document.caption : ""; if (newMsg.attachPath != null && newMsg.attachPath.startsWith(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE).getAbsolutePath())) { File cacheFile = new File(newMsg.attachPath); @@ -597,26 +612,7 @@ public class SecretChatHelper { } } - ArrayList arr = new ArrayList<>(); - arr.add(newMsg); - MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); - - //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.document, 4); - } else if (newMsg.media instanceof TLRPC.TL_messageMediaAudio && newMsg.media.audio != null) { - TLRPC.Audio audio = newMsg.media.audio; - newMsg.media.audio = new TLRPC.TL_audioEncrypted(); - newMsg.media.audio.id = file.id; - newMsg.media.audio.access_hash = file.access_hash; - newMsg.media.audio.user_id = audio.user_id; - newMsg.media.audio.date = audio.date; - newMsg.media.audio.duration = audio.duration; - newMsg.media.audio.size = file.size; - newMsg.media.audio.dc_id = file.dc_id; - newMsg.media.audio.key = decryptedMessage.media.key; - newMsg.media.audio.iv = decryptedMessage.media.iv; - newMsg.media.audio.mime_type = audio.mime_type; - - String fileName = audio.dc_id + "_" + audio.id + ".ogg"; + /*String fileName = audio.dc_id + "_" + audio.id + ".ogg"; TODO check String fileName2 = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".ogg"; if (!fileName.equals(fileName2)) { File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); @@ -624,11 +620,14 @@ public class SecretChatHelper { if (cacheFile.renameTo(cacheFile2)) { newMsg.attachPath = ""; } - } + }*/ ArrayList arr = new ArrayList<>(); arr.add(newMsg); MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + + //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.document, 4); document + //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.video, 5); video } } } @@ -649,178 +648,203 @@ public class SecretChatHelper { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { - TLObject toEncryptObject; - if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { - TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); - int myLayer = Math.max(17, AndroidUtilities.getMyLayerVersion(chat.layer)); - layer.layer = Math.min(myLayer, AndroidUtilities.getPeerLayerVersion(chat.layer)); - layer.message = req; - layer.random_bytes = new byte[15]; - Utilities.random.nextBytes(layer.random_bytes); - toEncryptObject = layer; + try { + TLObject toEncryptObject; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { + TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); + int myLayer = Math.max(17, AndroidUtilities.getMyLayerVersion(chat.layer)); + layer.layer = Math.min(myLayer, AndroidUtilities.getPeerLayerVersion(chat.layer)); + layer.message = req; + layer.random_bytes = new byte[15]; + Utilities.random.nextBytes(layer.random_bytes); + toEncryptObject = layer; - if (chat.seq_in == 0 && chat.seq_out == 0) { - if (chat.admin_id == UserConfig.getClientUserId()) { - chat.seq_out = 1; - } else { - chat.seq_in = 1; - } - } - - if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { - layer.in_seq_no = chat.seq_in; - layer.out_seq_no = chat.seq_out; - chat.seq_out += 2; - if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { - if (chat.key_create_date == 0) { - chat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); - } - chat.key_use_count_out++; - if ((chat.key_use_count_out >= 100 || chat.key_create_date < ConnectionsManager.getInstance().getCurrentTime() - 60 * 60 * 24 * 7) && chat.exchange_id == 0 && chat.future_key_fingerprint == 0) { - requestNewSecretChatKey(chat); - } - } - MessagesStorage.getInstance().updateEncryptedChatSeq(chat); - if (newMsgObj != null) { - newMsgObj.seq_in = layer.in_seq_no; - newMsgObj.seq_out = layer.out_seq_no; - MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); - } - } else { - layer.in_seq_no = newMsgObj.seq_in; - layer.out_seq_no = newMsgObj.seq_out; - } - FileLog.e("tmessages", req + " send message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); - } else { - toEncryptObject = req; - } - - - int len = toEncryptObject.getObjectSize(); - NativeByteBuffer toEncrypt = new NativeByteBuffer(4 + len); - toEncrypt.writeInt32(len); - toEncryptObject.serializeToStream(toEncrypt); - - byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); - byte[] messageKey = new byte[16]; - if (messageKeyFull.length != 0) { - System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); - } - - MessageKeyData keyData = MessageKeyData.generateMessageKeyData(chat.auth_key, messageKey, false); - - len = toEncrypt.length(); - int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; - NativeByteBuffer dataForEncryption = new NativeByteBuffer(len + extraLen); - toEncrypt.position(0); - dataForEncryption.writeBytes(toEncrypt); - if (extraLen != 0) { - byte[] b = new byte[extraLen]; - Utilities.random.nextBytes(b); - dataForEncryption.writeBytes(b); - } - toEncrypt.reuse(); - - Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); - - NativeByteBuffer data = new NativeByteBuffer(8 + messageKey.length + dataForEncryption.length()); - dataForEncryption.position(0); - data.writeInt64(chat.key_fingerprint); - data.writeBytes(messageKey); - data.writeBytes(dataForEncryption); - dataForEncryption.reuse(); - data.position(0); - - TLObject reqToSend; - - if (encryptedFile == null) { - if (req instanceof TLRPC.TL_decryptedMessageService) { - TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - reqToSend = req2; - } else { - TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - reqToSend = req2; - } - } else { - TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); - req2.data = data; - req2.random_id = req.random_id; - req2.peer = new TLRPC.TL_inputEncryptedChat(); - req2.peer.chat_id = chat.id; - req2.peer.access_hash = chat.access_hash; - req2.file = encryptedFile; - reqToSend = req2; - } - ConnectionsManager.getInstance().sendRequest(reqToSend, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { - TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id); - sendingNotifyLayer.remove((Integer) currentChat.id); - currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); - MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat); - } - } - if (newMsgObj != null) { - if (error == null) { - final String attachPath = newMsgObj.attachPath; - final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; - if (isSecretVisibleMessage(newMsgObj)) { - newMsgObj.date = res.date; - } - if (res.file instanceof TLRPC.TL_encryptedFile) { - processSentMessage(newMsgObj, res.file, req, originalPath); - } - MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - if (isSecretInvisibleMessage(newMsgObj)) { - res.date = 0; - } - MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false, 0); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id); - SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { - SendMessagesHelper.getInstance().stopVideoService(attachPath); - } - SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); - } - }); - } - }); + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; } else { - MessagesStorage.getInstance().markMessageAsSendError(newMsgObj); - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; - NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); - SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { - SendMessagesHelper.getInstance().stopVideoService(newMsgObj.attachPath); - } - SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); - } - }); + chat.seq_in = 1; } } + + if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { + layer.in_seq_no = chat.seq_in; + layer.out_seq_no = chat.seq_out; + chat.seq_out += 2; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { + if (chat.key_create_date == 0) { + chat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + } + chat.key_use_count_out++; + if ((chat.key_use_count_out >= 100 || chat.key_create_date < ConnectionsManager.getInstance().getCurrentTime() - 60 * 60 * 24 * 7) && chat.exchange_id == 0 && chat.future_key_fingerprint == 0) { + requestNewSecretChatKey(chat); + } + } + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + if (newMsgObj != null) { + newMsgObj.seq_in = layer.in_seq_no; + newMsgObj.seq_out = layer.out_seq_no; + MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); + } + } else { + layer.in_seq_no = newMsgObj.seq_in; + layer.out_seq_no = newMsgObj.seq_out; + } + FileLog.e("tmessages", req + " send message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + } else { + toEncryptObject = req; } - }, ConnectionsManager.RequestFlagInvokeAfter); + + + int len = toEncryptObject.getObjectSize(); + NativeByteBuffer toEncrypt = new NativeByteBuffer(4 + len); + toEncrypt.writeInt32(len); + toEncryptObject.serializeToStream(toEncrypt); + + byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); + byte[] messageKey = new byte[16]; + if (messageKeyFull.length != 0) { + System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); + } + + MessageKeyData keyData = MessageKeyData.generateMessageKeyData(chat.auth_key, messageKey, false); + + len = toEncrypt.length(); + int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; + NativeByteBuffer dataForEncryption = new NativeByteBuffer(len + extraLen); + toEncrypt.position(0); + dataForEncryption.writeBytes(toEncrypt); + if (extraLen != 0) { + byte[] b = new byte[extraLen]; + Utilities.random.nextBytes(b); + dataForEncryption.writeBytes(b); + } + toEncrypt.reuse(); + + Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); + + NativeByteBuffer data = new NativeByteBuffer(8 + messageKey.length + dataForEncryption.length()); + dataForEncryption.position(0); + data.writeInt64(chat.key_fingerprint); + data.writeBytes(messageKey); + data.writeBytes(dataForEncryption); + dataForEncryption.reuse(); + data.position(0); + + TLObject reqToSend; + + if (encryptedFile == null) { + if (req instanceof TLRPC.TL_decryptedMessageService) { + TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } else { + TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } + } else { + TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + req2.file = encryptedFile; + reqToSend = req2; + } + ConnectionsManager.getInstance().sendRequest(reqToSend, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id); + if (currentChat == null) { + currentChat = chat; + } + + if (currentChat.key_hash == null) { + currentChat.key_hash = AndroidUtilities.calcAuthKeyHash(currentChat.auth_key); + } + + if (AndroidUtilities.getPeerLayerVersion(currentChat.layer) >= 46 && currentChat.key_hash.length == 16) { + try { + byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); + byte[] key_hash = new byte[36]; + System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); + System.arraycopy(sha256, 0, key_hash, 16, 20); + currentChat.key_hash = key_hash; + MessagesStorage.getInstance().updateEncryptedChat(currentChat); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + sendingNotifyLayer.remove((Integer) currentChat.id); + currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); + MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat); + } + } + if (newMsgObj != null) { + if (error == null) { + final String attachPath = newMsgObj.attachPath; + final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; + if (isSecretVisibleMessage(newMsgObj)) { + newMsgObj.date = res.date; + } + if (res.file instanceof TLRPC.TL_encryptedFile) { + processSentMessage(newMsgObj, res.file, req, originalPath); + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + if (isSecretInvisibleMessage(newMsgObj)) { + res.date = 0; + } + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false, 0); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id); + SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance().stopVideoService(attachPath); + } + SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); + } + }); + } + }); + } else { + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance().stopVideoService(newMsgObj.attachPath); + } + SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); + } + }); + } + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } }); } @@ -859,6 +883,7 @@ public class SecretChatHelper { if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { newMessage = new TLRPC.TL_message_secret(); newMessage.ttl = decryptedMessage.ttl; + newMessage.entities = decryptedMessage.entities; } else { newMessage = new TLRPC.TL_message(); newMessage.ttl = chat.ttl; @@ -873,10 +898,22 @@ public class SecretChatHelper { newMessage.to_id.user_id = UserConfig.getClientUserId(); newMessage.unread = true; newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + if (decryptedMessage.via_bot_name != null && decryptedMessage.via_bot_name.length() > 0) { + newMessage.via_bot_name = decryptedMessage.via_bot_name; + newMessage.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } newMessage.dialog_id = ((long) chat.id) << 32; - if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { + if (decryptedMessage.reply_to_random_id != 0) { + newMessage.reply_to_random_id = decryptedMessage.reply_to_random_id; + newMessage.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + if (decryptedMessage.media == null || decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { newMessage.media = new TLRPC.TL_messageMediaEmpty(); - } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) { + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaWebPage) { + newMessage.media = new TLRPC.TL_messageMediaWebPage(); + newMessage.media.webpage = new TLRPC.TL_webPageUrlPending(); + newMessage.media.webpage.url = decryptedMessage.media.url; + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) { newMessage.media = new TLRPC.TL_messageMediaContact(); newMessage.media.last_name = decryptedMessage.media.last_name; newMessage.media.first_name = decryptedMessage.media.first_name; @@ -892,7 +929,7 @@ public class SecretChatHelper { return null; } newMessage.media = new TLRPC.TL_messageMediaPhoto(); - newMessage.media.caption = ""; + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; newMessage.media.photo = new TLRPC.TL_photo(); newMessage.media.photo.date = newMessage.date; byte[] thumb = ((TLRPC.TL_decryptedMessageMediaPhoto) decryptedMessage.media).thumb; @@ -923,51 +960,57 @@ public class SecretChatHelper { if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { return null; } - newMessage.media = new TLRPC.TL_messageMediaVideo(); - newMessage.media.caption = ""; - newMessage.media.video = new TLRPC.TL_videoEncrypted(); + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.document = new TLRPC.TL_documentEncrypted(); + newMessage.media.document.key = decryptedMessage.media.key; + newMessage.media.document.iv = decryptedMessage.media.iv; + newMessage.media.document.dc_id = file.dc_id; + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + newMessage.media.document.date = date; + newMessage.media.document.size = file.size; + newMessage.media.document.id = file.id; + newMessage.media.document.access_hash = file.access_hash; + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = "video/mp4"; + } byte[] thumb = ((TLRPC.TL_decryptedMessageMediaVideo) decryptedMessage.media).thumb; if (thumb != null && thumb.length != 0 && thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { - newMessage.media.video.thumb = new TLRPC.TL_photoCachedSize(); - newMessage.media.video.thumb.bytes = thumb; - newMessage.media.video.thumb.w = decryptedMessage.media.thumb_w; - newMessage.media.video.thumb.h = decryptedMessage.media.thumb_h; - newMessage.media.video.thumb.type = "s"; - newMessage.media.video.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize(); + newMessage.media.document.thumb.bytes = thumb; + newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w; + newMessage.media.document.thumb.h = decryptedMessage.media.thumb_h; + newMessage.media.document.thumb.type = "s"; + newMessage.media.document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); } else { - newMessage.media.video.thumb = new TLRPC.TL_photoSizeEmpty(); - newMessage.media.video.thumb.type = "s"; + newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + newMessage.media.document.thumb.type = "s"; } - newMessage.media.video.duration = decryptedMessage.media.duration; - newMessage.media.video.dc_id = file.dc_id; - newMessage.media.video.w = decryptedMessage.media.w; - newMessage.media.video.h = decryptedMessage.media.h; - newMessage.media.video.date = date; - newMessage.media.video.size = file.size; - newMessage.media.video.id = file.id; - newMessage.media.video.access_hash = file.access_hash; - newMessage.media.video.key = decryptedMessage.media.key; - newMessage.media.video.iv = decryptedMessage.media.iv; - newMessage.media.video.mime_type = decryptedMessage.media.mime_type; - newMessage.media.video.caption = ""; + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.w = decryptedMessage.media.w; + attributeVideo.h = decryptedMessage.media.h; + attributeVideo.duration = decryptedMessage.media.duration; + newMessage.media.document.attributes.add(attributeVideo); if (newMessage.ttl != 0) { - newMessage.ttl = Math.max(newMessage.media.video.duration + 1, newMessage.ttl); - } - if (newMessage.media.video.mime_type == null) { - newMessage.media.video.mime_type = "video/mp4"; + newMessage.ttl = Math.max(decryptedMessage.media.duration + 2, newMessage.ttl); } } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) { if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { return null; } newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; newMessage.media.document = new TLRPC.TL_documentEncrypted(); newMessage.media.document.id = file.id; newMessage.media.document.access_hash = file.access_hash; newMessage.media.document.date = date; - TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); - fileName.file_name = decryptedMessage.media.file_name; - newMessage.media.document.attributes.add(fileName); + if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument_layer8) { + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = decryptedMessage.media.file_name; + newMessage.media.document.attributes.add(fileName); + } else { + newMessage.media.document.attributes = decryptedMessage.media.attributes; + } newMessage.media.document.mime_type = decryptedMessage.media.mime_type; newMessage.media.document.size = file.size; newMessage.media.document.key = decryptedMessage.media.key; @@ -988,8 +1031,12 @@ public class SecretChatHelper { newMessage.media.document.thumb.type = "s"; } newMessage.media.document.dc_id = file.dc_id; + if (MessageObject.isVoiceMessage(newMessage)) { + newMessage.media_unread = true; + } } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaExternalDocument) { newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.caption = ""; newMessage.media.document = new TLRPC.TL_document(); newMessage.media.document.id = decryptedMessage.media.id; newMessage.media.document.access_hash = decryptedMessage.media.access_hash; @@ -1006,24 +1053,38 @@ public class SecretChatHelper { if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { return null; } - newMessage.media = new TLRPC.TL_messageMediaAudio(); - newMessage.media.audio = new TLRPC.TL_audioEncrypted(); - newMessage.media.audio.id = file.id; - newMessage.media.audio.access_hash = file.access_hash; - newMessage.media.audio.user_id = from_id; - newMessage.media.audio.date = date; - newMessage.media.audio.size = file.size; - newMessage.media.audio.key = decryptedMessage.media.key; - newMessage.media.audio.iv = decryptedMessage.media.iv; - newMessage.media.audio.dc_id = file.dc_id; - newMessage.media.audio.duration = decryptedMessage.media.duration; - newMessage.media.audio.mime_type = decryptedMessage.media.mime_type; + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.document = new TLRPC.TL_documentEncrypted(); + newMessage.media.document.key = decryptedMessage.media.key; + newMessage.media.document.iv = decryptedMessage.media.iv; + newMessage.media.document.id = file.id; + newMessage.media.document.access_hash = file.access_hash; + newMessage.media.document.date = date; + newMessage.media.document.size = file.size; + newMessage.media.document.dc_id = file.dc_id; + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + newMessage.media.document.thumb.type = "s"; + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = "audio/ogg"; + } + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.duration = decryptedMessage.media.duration; + attributeAudio.voice = true; + newMessage.media.document.attributes.add(attributeAudio); if (newMessage.ttl != 0) { - newMessage.ttl = Math.max(newMessage.media.audio.duration + 1, newMessage.ttl); - } - if (newMessage.media.audio.mime_type == null) { - newMessage.media.audio.mime_type = "audio/ogg"; + newMessage.ttl = Math.max(decryptedMessage.media.duration + 1, newMessage.ttl); } + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVenue) { + newMessage.media = new TLRPC.TL_messageMediaVenue(); + newMessage.media.geo = new TLRPC.TL_geoPoint(); + newMessage.media.geo.lat = decryptedMessage.media.lat; + newMessage.media.geo._long = decryptedMessage.media._long; + newMessage.media.title = decryptedMessage.media.title; + newMessage.media.address = decryptedMessage.media.address; + newMessage.media.provider = decryptedMessage.media.provider; + newMessage.media.venue_id = decryptedMessage.media.venue_id; } else { return null; } @@ -1091,15 +1152,34 @@ public class SecretChatHelper { return null; } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) { if (!serviceMessage.action.random_ids.isEmpty()) { - MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), ConnectionsManager.getInstance().getCurrentTime(), 1, serviceMessage.action.random_ids); + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 1, serviceMessage.action.random_ids); } } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer); + if (chat.key_hash.length == 16 && currentPeerLayer >= 46) { + try { + byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); + byte[] key_hash = new byte[36]; + System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); + System.arraycopy(sha256, 0, key_hash, 16, 20); + chat.key_hash = key_hash; + MessagesStorage.getInstance().updateEncryptedChat(chat); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer); MessagesStorage.getInstance().updateEncryptedChatLayer(chat); if (currentPeerLayer < CURRENT_SECRET_CHAT_LAYER) { sendNotifyLayerMessage(chat, null); } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, chat); + } + }); } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionRequestKey) { if (chat.exchange_id != 0) { if (chat.exchange_id > serviceMessage.action.exchange_id) { @@ -1274,13 +1354,13 @@ public class SecretChatHelper { } public void checkSecretHoles(TLRPC.EncryptedChat chat, ArrayList messages) { - ArrayList holes = secretHolesQueue.get(chat.id); + ArrayList holes = secretHolesQueue.get(chat.id); if (holes == null) { return; } - Collections.sort(holes, new Comparator() { + Collections.sort(holes, new Comparator() { @Override - public int compare(TLRPC.TL_decryptedMessageHolder lhs, TLRPC.TL_decryptedMessageHolder rhs) { + public int compare(TL_decryptedMessageHolder lhs, TL_decryptedMessageHolder rhs) { if (lhs.layer.out_seq_no > rhs.layer.out_seq_no) { return 1; } else if (lhs.layer.out_seq_no < rhs.layer.out_seq_no) { @@ -1292,7 +1372,7 @@ public class SecretChatHelper { boolean update = false; for (int a = 0; a < holes.size(); a++) { - TLRPC.TL_decryptedMessageHolder holder = holes.get(a); + TL_decryptedMessageHolder holder = holes.get(a); if (holder.layer.out_seq_no == chat.seq_in || chat.seq_in == holder.layer.out_seq_no - 2) { chat.seq_in = holder.layer.out_seq_no; holes.remove(a); @@ -1321,112 +1401,117 @@ public class SecretChatHelper { return null; } - NativeByteBuffer is = new NativeByteBuffer(message.bytes.length); - is.writeBytes(message.bytes); - is.position(0); - long fingerprint = is.readInt64(false); - byte[] keyToDecrypt = null; - boolean new_key_used = false; - if (chat.key_fingerprint == fingerprint) { - keyToDecrypt = chat.auth_key; - } else if (chat.future_key_fingerprint != 0 && chat.future_key_fingerprint == fingerprint) { - keyToDecrypt = chat.future_auth_key; - new_key_used = true; - } - - if (keyToDecrypt != null) { - byte[] messageKey = is.readData(16, false); - MessageKeyData keyData = MessageKeyData.generateMessageKeyData(keyToDecrypt, messageKey, false); - - Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24); - - int len = is.readInt32(false); - if (len < 0 || len > is.limit() - 28) { - return null; - } - byte[] messageKeyFull = Utilities.computeSHA1(is.buffer, 24, Math.min(len + 4 + 24, is.buffer.limit())); - if (!Utilities.arraysEquals(messageKey, 0, messageKeyFull, messageKeyFull.length - 16)) { - return null; + try { + NativeByteBuffer is = new NativeByteBuffer(message.bytes.length); + is.writeBytes(message.bytes); + is.position(0); + long fingerprint = is.readInt64(false); + byte[] keyToDecrypt = null; + boolean new_key_used = false; + if (chat.key_fingerprint == fingerprint) { + keyToDecrypt = chat.auth_key; + } else if (chat.future_key_fingerprint != 0 && chat.future_key_fingerprint == fingerprint) { + keyToDecrypt = chat.future_auth_key; + new_key_used = true; } - TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32(false), false); + if (keyToDecrypt != null) { + byte[] messageKey = is.readData(16, false); + MessageKeyData keyData = MessageKeyData.generateMessageKeyData(keyToDecrypt, messageKey, false); - is.reuse(); - if (!new_key_used && AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { - chat.key_use_count_in++; - } - if (object instanceof TLRPC.TL_decryptedMessageLayer) { - final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer) object; - if (chat.seq_in == 0 && chat.seq_out == 0) { - if (chat.admin_id == UserConfig.getClientUserId()) { - chat.seq_out = 1; - } else { - chat.seq_in = 1; - } - } - if (layer.random_bytes.length < 15) { - FileLog.e("tmessages", "got random bytes less than needed"); + Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24); + + int len = is.readInt32(false); + if (len < 0 || len > is.limit() - 28) { return null; } - FileLog.e("tmessages", "current chat in_seq = " + chat.seq_in + " out_seq = " + chat.seq_out); - FileLog.e("tmessages", "got message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); - if (layer.out_seq_no < chat.seq_in) { + byte[] messageKeyFull = Utilities.computeSHA1(is.buffer, 24, Math.min(len + 4 + 24, is.buffer.limit())); + if (!Utilities.arraysEquals(messageKey, 0, messageKeyFull, messageKeyFull.length - 16)) { return null; } - if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) { - FileLog.e("tmessages", "got hole"); - ArrayList arr = secretHolesQueue.get(chat.id); - if (arr == null) { - arr = new ArrayList<>(); - secretHolesQueue.put(chat.id, arr); + + TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32(false), false); + + is.reuse(); + if (!new_key_used && AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { + chat.key_use_count_in++; + } + if (object instanceof TLRPC.TL_decryptedMessageLayer) { + final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer) object; + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; + } else { + chat.seq_in = 1; + } } - if (arr.size() >= 4) { - secretHolesQueue.remove(chat.id); - final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); - newChat.id = chat.id; - newChat.user_id = chat.user_id; - newChat.auth_key = chat.auth_key; - newChat.key_create_date = chat.key_create_date; - newChat.key_use_count_in = chat.key_use_count_in; - newChat.key_use_count_out = chat.key_use_count_out; - newChat.seq_in = chat.seq_in; - newChat.seq_out = chat.seq_out; - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - MessagesController.getInstance().putEncryptedChat(newChat, false); - MessagesStorage.getInstance().updateEncryptedChat(newChat); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); - } - }); - declineSecretChat(chat.id); + if (layer.random_bytes.length < 15) { + FileLog.e("tmessages", "got random bytes less than needed"); return null; } + FileLog.e("tmessages", "current chat in_seq = " + chat.seq_in + " out_seq = " + chat.seq_out); + FileLog.e("tmessages", "got message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + if (layer.out_seq_no < chat.seq_in) { + return null; + } + if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) { + FileLog.e("tmessages", "got hole"); + ArrayList arr = secretHolesQueue.get(chat.id); + if (arr == null) { + arr = new ArrayList<>(); + secretHolesQueue.put(chat.id, arr); + } + if (arr.size() >= 4) { + secretHolesQueue.remove(chat.id); + final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); + newChat.id = chat.id; + newChat.user_id = chat.user_id; + newChat.auth_key = chat.auth_key; + newChat.key_create_date = chat.key_create_date; + newChat.key_use_count_in = chat.key_use_count_in; + newChat.key_use_count_out = chat.key_use_count_out; + newChat.seq_in = chat.seq_in; + newChat.seq_out = chat.seq_out; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(newChat, false); + MessagesStorage.getInstance().updateEncryptedChat(newChat); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + declineSecretChat(chat.id); + return null; + } - TLRPC.TL_decryptedMessageHolder holder = new TLRPC.TL_decryptedMessageHolder(); - holder.layer = layer; - holder.file = message.file; - holder.random_id = message.random_id; - holder.date = message.date; - holder.new_key_used = new_key_used; - arr.add(holder); - return null; + TL_decryptedMessageHolder holder = new TL_decryptedMessageHolder(); + holder.layer = layer; + holder.file = message.file; + holder.random_id = message.random_id; + holder.date = message.date; + holder.new_key_used = new_key_used; + arr.add(holder); + return null; + } + chat.seq_in = layer.out_seq_no; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + object = layer.message; } - chat.seq_in = layer.out_seq_no; - MessagesStorage.getInstance().updateEncryptedChatSeq(chat); - object = layer.message; + ArrayList messages = new ArrayList<>(); + TLRPC.Message decryptedMessage = processDecryptedObject(chat, message.file, message.date, message.random_id, object, new_key_used); + if (decryptedMessage != null) { + messages.add(decryptedMessage); + } + checkSecretHoles(chat, messages); + return messages; + } else { + is.reuse(); + FileLog.e("tmessages", "fingerprint mismatch " + fingerprint); } - ArrayList messages = new ArrayList<>(); - TLRPC.Message decryptedMessage = processDecryptedObject(chat, message.file, message.date, message.random_id, object, new_key_used); - if (decryptedMessage != null) { - messages.add(decryptedMessage); - } - checkSecretHoles(chat, messages); - return messages; - } else { - is.reuse(); - FileLog.e("tmessages", "fingerprint mismatch " + fingerprint); + } catch (Exception e) { + FileLog.e("tmessages", e); } + return null; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 8f9e5bb6e..05c96ff7a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -8,6 +8,10 @@ package org.telegram.messenger; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; @@ -20,11 +24,13 @@ import android.webkit.MimeTypeMap; import android.widget.Toast; import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.messenger.query.StickersQuery; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.QuickAckDelegate; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; import java.io.File; import java.io.RandomAccessFile; @@ -46,8 +52,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter public int type; public String originalPath; public TLRPC.FileLocation location; - public TLRPC.TL_video videoLocation; - public TLRPC.TL_audio audioLocation; public TLRPC.TL_document documentLocation; public String httpLocation; public MessageObject obj; @@ -78,6 +82,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter NotificationCenter.getInstance().addObserver(this, NotificationCenter.FilePreparingFailed); NotificationCenter.getInstance().addObserver(this, NotificationCenter.httpFileDidFailedLoad); NotificationCenter.getInstance().addObserver(this, NotificationCenter.httpFileDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); } public void cleanUp() { @@ -211,7 +217,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (message.obj == messageObject) { message.obj.videoEditedInfo = null; message.obj.messageOwner.message = "-1"; - message.obj.messageOwner.media.video.size = (int) finalSize; + message.obj.messageOwner.media.document.size = (int) finalSize; ArrayList messages = new ArrayList<>(); messages.add(message.obj.messageOwner); @@ -248,7 +254,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else if (id == NotificationCenter.httpFileDidLoaded) { String path = (String) args[0]; - String file = (String) args[1]; ArrayList arr = delayedMessages.get(path); if (arr != null) { for (int a = 0; a < arr.size(); a++) { @@ -325,7 +330,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } delayedMessages.remove(path); } - } else if (id == NotificationCenter.httpFileDidFailedLoad) { + } else if (id == NotificationCenter.FileDidLoaded) { + String path = (String) args[0]; + ArrayList arr = delayedMessages.get(path); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + performSendDelayedMessage(arr.get(a)); + } + delayedMessages.remove(path); + } + } else if (id == NotificationCenter.httpFileDidFailedLoad || id == NotificationCenter.FileDidFailedLoad) { String path = (String) args[0]; ArrayList arr = delayedMessages.get(path); @@ -423,7 +437,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (unsent) { unsentMessages.put(messageObject.getId(), messageObject); } - sendMessage(messageObject, messageObject.messageOwner.from_id < 0); + sendMessage(messageObject, messageObject.messageOwner.post); return true; } @@ -442,13 +456,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (messageObject.messageOwner.media != null && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage)) { if (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo) { sendMessage((TLRPC.TL_photo) messageObject.messageOwner.media.photo, null, did, messageObject.replyMessageObject, asAdmin, null); - } else if (messageObject.messageOwner.media.audio instanceof TLRPC.TL_audio) { - sendMessage((TLRPC.TL_audio) messageObject.messageOwner.media.audio, messageObject.messageOwner.attachPath, did, messageObject.replyMessageObject, asAdmin); - } else if (messageObject.messageOwner.media.video instanceof TLRPC.TL_video) { - TLRPC.TL_video video = (TLRPC.TL_video) messageObject.messageOwner.media.video; - sendMessage(video, messageObject.videoEditedInfo, messageObject.messageOwner.attachPath, did, messageObject.replyMessageObject, asAdmin, null); } else if (messageObject.messageOwner.media.document instanceof TLRPC.TL_document) { - sendMessage((TLRPC.TL_document) messageObject.messageOwner.media.document, messageObject.messageOwner.attachPath, did, messageObject.replyMessageObject, asAdmin, null); + sendMessage((TLRPC.TL_document) messageObject.messageOwner.media.document, null, messageObject.messageOwner.attachPath, did, messageObject.replyMessageObject, asAdmin, null); } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { sendMessage(messageObject.messageOwner.media, did, messageObject.replyMessageObject, asAdmin); } else if (messageObject.messageOwner.media.phone_number != null) { @@ -480,54 +489,73 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (document == null) { return; } - if (((int) peer) == 0 && document.thumb instanceof TLRPC.TL_photoSize) { - File file = FileLoader.getPathToAttach(document.thumb, true); - if (file.exists()) { - try { - int len = (int) file.length(); - byte[] arr = new byte[(int) file.length()]; - RandomAccessFile reader = new RandomAccessFile(file, "r"); - reader.readFully(arr); - TLRPC.TL_document newDocument = new TLRPC.TL_document(); - newDocument.thumb = new TLRPC.TL_photoCachedSize(); - newDocument.thumb.location = document.thumb.location; - newDocument.thumb.size = document.thumb.size; - newDocument.thumb.w = document.thumb.w; - newDocument.thumb.h = document.thumb.h; - newDocument.thumb.type = document.thumb.type; - newDocument.thumb.bytes = arr; + if ((int) peer == 0) { + int high_id = (int) (peer >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + if (document.thumb instanceof TLRPC.TL_photoSize) { + File file = FileLoader.getPathToAttach(document.thumb, true); + if (file.exists()) { + try { + int len = (int) file.length(); + byte[] arr = new byte[(int) file.length()]; + RandomAccessFile reader = new RandomAccessFile(file, "r"); + reader.readFully(arr); + TLRPC.TL_document newDocument = new TLRPC.TL_document(); + newDocument.thumb = new TLRPC.TL_photoCachedSize(); + newDocument.thumb.location = document.thumb.location; + newDocument.thumb.size = document.thumb.size; + newDocument.thumb.w = document.thumb.w; + newDocument.thumb.h = document.thumb.h; + newDocument.thumb.type = document.thumb.type; + newDocument.thumb.bytes = arr; - newDocument.id = document.id; - newDocument.access_hash = document.access_hash; - newDocument.date = document.date; - newDocument.mime_type = document.mime_type; - newDocument.size = document.size; - newDocument.dc_id = document.dc_id; - newDocument.attributes = document.attributes; - if (newDocument.mime_type == null) { - newDocument.mime_type = ""; + newDocument.id = document.id; + newDocument.access_hash = document.access_hash; + newDocument.date = document.date; + newDocument.mime_type = document.mime_type; + newDocument.size = document.size; + newDocument.dc_id = document.dc_id; + newDocument.attributes = document.attributes; + if (newDocument.mime_type == null) { + newDocument.mime_type = ""; + } + document = newDocument; + } catch (Exception e) { + FileLog.e("tmessages", e); } - document = newDocument; - } catch (Exception e) { - FileLog.e("tmessages", e); } } - } - if ((int) peer == 0) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { - document.attributes.remove(a); - document.attributes.add(new TLRPC.TL_documentAttributeSticker_old()); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) < 46) { + document.attributes.remove(a); + document.attributes.add(new TLRPC.TL_documentAttributeSticker_old()); + } else { + if (attribute.stickerset != null) { + String name = StickersQuery.getStickerSetName(attribute.stickerset.id); + if (name != null && name.length() > 0) { + attribute.stickerset = new TLRPC.TL_inputStickerSetShortName(); + attribute.stickerset.short_name = name; + } else { + attribute.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } + } else { + attribute.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } + } break; } } } - SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) document, null, peer, replyingMessageObject, asAdmin, null); + SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) document, null, null, peer, replyingMessageObject, asAdmin, null); } public void sendMessage(TLRPC.User user, long peer, MessageObject reply_to_msg, boolean asAdmin) { - sendMessage(null, null, null, null, null, user, null, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, null); + sendMessage(null, null, null, null, user, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, null); } public void sendMessage(ArrayList messages, final long peer, boolean asAdmin) { @@ -537,6 +565,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter int lower_id = (int) peer; final TLRPC.Peer to_id = MessagesController.getPeer((int) peer); boolean isMegagroup = false; + boolean isSignature = false; if (lower_id > 0) { TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id); if (sendToUser == null) { @@ -544,7 +573,10 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); - isMegagroup = ChatObject.isChannel(chat) && chat.megagroup; + if (ChatObject.isChannel(chat)) { + isMegagroup = chat.megagroup; + isSignature = chat.signatures; + } } ArrayList objArr = new ArrayList<>(); @@ -559,22 +591,28 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (msgObj.getId() <= 0) { continue; } - if (BuildVars.DEBUG_VERSION) { - FileLog.d("tmessages", "forward message with id = " + msgObj.getId()); - } final TLRPC.Message newMsg = new TLRPC.TL_message(); if (msgObj.isForwarded()) { - newMsg.fwd_from_id = msgObj.messageOwner.fwd_from_id; - newMsg.fwd_date = msgObj.messageOwner.fwd_date; + newMsg.fwd_from = msgObj.messageOwner.fwd_from; } else { - if (msgObj.messageOwner.from_id > 0) { - newMsg.fwd_from_id = new TLRPC.TL_peerUser(); - newMsg.fwd_from_id.user_id = msgObj.messageOwner.from_id; + newMsg.fwd_from = new TLRPC.TL_messageFwdHeader(); + if (msgObj.isFromUser()) { + newMsg.fwd_from.from_id = msgObj.messageOwner.from_id; + newMsg.fwd_from.flags |= 1; } else { - newMsg.fwd_from_id = msgObj.messageOwner.to_id; + newMsg.fwd_from.channel_id = msgObj.messageOwner.to_id.channel_id; + newMsg.fwd_from.flags |= 2; + if (msgObj.messageOwner.post) { + newMsg.fwd_from.channel_post = msgObj.getId(); + newMsg.fwd_from.flags |= 4; + if (msgObj.messageOwner.from_id > 0) { + newMsg.fwd_from.from_id = msgObj.messageOwner.from_id; + newMsg.fwd_from.flags |= 1; + } + } } - newMsg.fwd_date = msgObj.messageOwner.date; + newMsg.date = msgObj.messageOwner.date; } newMsg.media = msgObj.messageOwner.media; newMsg.flags = TLRPC.MESSAGE_FLAG_FWD; @@ -601,7 +639,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); newMsg.out = true; if (asAdmin && to_id.channel_id != 0 && !isMegagroup) { - newMsg.from_id = -to_id.channel_id; + newMsg.from_id = isSignature ? UserConfig.getClientUserId() : -to_id.channel_id; + newMsg.post = true; } else { newMsg.from_id = UserConfig.getClientUserId(); newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_FROM_ID; @@ -613,9 +652,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter messagesByRandomIds.put(newMsg.random_id, newMsg); ids.add(newMsg.fwd_msg_id); newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); - if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { - newMsg.media_unread = true; - } if (inputPeer instanceof TLRPC.TL_inputPeerChannel) { if (asAdmin && !isMegagroup) { newMsg.views = 1; @@ -630,6 +666,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } newMsg.dialog_id = peer; newMsg.to_id = to_id; + if (MessageObject.isVoiceMessage(newMsg) && newMsg.to_id.channel_id == 0) { + newMsg.media_unread = true; + } if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { newMsg.ttl = -msgObj.messageOwner.to_id.channel_id; } @@ -651,11 +690,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter req.to_peer = inputPeer; if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { req.from_peer = MessagesController.getInputPeer(-msgObj.messageOwner.to_id.channel_id); + req.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); } else { req.from_peer = new TLRPC.TL_inputPeerEmpty(); } req.random_id = randomIds; req.id = ids; + if (asAdmin && req.to_peer.channel_id != 0 && !isMegagroup) { req.broadcast = true; } @@ -717,7 +758,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter removeFromSendingMessages(oldId); } }); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + if (MessageObject.isVideoMessage(newMsgObj)) { stopVideoService(newMsgObj.attachPath); } } @@ -744,7 +785,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); processSentMessage(newMsgObj.id); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + if (MessageObject.isVideoMessage(newMsgObj)) { stopVideoService(newMsgObj.attachPath); } removeFromSendingMessages(newMsgObj.id); @@ -765,35 +806,96 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } - public void sendMessage(MessageObject retryMessageObject, boolean asAdmin) { - sendMessage(null, null, null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, true, asAdmin, retryMessageObject, null, retryMessageObject.messageOwner.params); + public void editMessage(MessageObject messageObject, String message, boolean searchLinks, final BaseFragment fragment) { + if (fragment == null || fragment.getParentActivity() == null) { + return; + } + final ProgressDialog progressDialog = new ProgressDialog(fragment.getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + TLRPC.TL_channels_editMessage req = new TLRPC.TL_channels_editMessage(); + req.channel = MessagesController.getInputChannel(messageObject.messageOwner.to_id.channel_id); + req.message = message; + req.id = messageObject.getId(); + req.no_webpage = !searchLinks; + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!fragment.getParentActivity().isFinishing()) { + progressDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + if (error == null) { + MessagesController.getInstance().processUpdates((TLRPC.Updates) response, false); + } else { + if (!error.text.equals("MESSAGE_NOT_MODIFIED")) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + fragment.showDialog(builder.create()); + } + }); + } + } + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } } - public void sendMessage(TLRPC.TL_document document, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, HashMap params) { - sendMessage(null, null, null, null, null, null, document, null, peer, path, reply_to_msg, null, true, asAdmin, null, null, params); + public void sendMessage(MessageObject retryMessageObject, boolean asAdmin) { + sendMessage(null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, true, asAdmin, retryMessageObject, null, retryMessageObject.messageOwner.params); + } + + public void sendMessage(TLRPC.TL_document document, VideoEditedInfo videoEditedInfo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, HashMap params) { + sendMessage(null, null, null, videoEditedInfo, null, document, peer, path, reply_to_msg, null, true, asAdmin, null, null, params); } public void sendMessage(String message, long peer, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, ArrayList entities, HashMap params) { - sendMessage(message, null, null, null, null, null, null, null, peer, null, reply_to_msg, webPage, searchLinks, asAdmin, null, entities, params); + sendMessage(message, null, null, null, null, null, peer, null, reply_to_msg, webPage, searchLinks, asAdmin, null, entities, params); } public void sendMessage(TLRPC.MessageMedia location, long peer, MessageObject reply_to_msg, boolean asAdmin) { - sendMessage(null, location, null, null, null, null, null, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, null); + sendMessage(null, location, null, null, null, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, null); } public void sendMessage(TLRPC.TL_photo photo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, HashMap params) { - sendMessage(null, null, photo, null, null, null, null, null, peer, path, reply_to_msg, null, true, asAdmin, null, null, params); + sendMessage(null, null, photo, null, null, null, peer, path, reply_to_msg, null, true, asAdmin, null, null, params); } - public void sendMessage(TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, HashMap params) { + /*public void sendMessage(TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, HashMap params) { sendMessage(null, null, null, video, videoEditedInfo, null, null, null, peer, path, reply_to_msg, null, true, asAdmin, null, null, params); - } + }*/ - public void sendMessage(TLRPC.TL_audio audio, String path, long peer, MessageObject reply_to_msg, boolean asAdmin) { - sendMessage(null, null, null, null, null, null, null, audio, peer, path, reply_to_msg, null, true, asAdmin, null, null, null); - } - - private void sendMessage(String message, TLRPC.MessageMedia location, TLRPC.TL_photo photo, TLRPC.TL_video video, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, long peer, String path, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, MessageObject retryMessageObject, ArrayList entities, HashMap params) { + private void sendMessage(String message, TLRPC.MessageMedia location, TLRPC.TL_photo photo, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, long peer, String path, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, MessageObject retryMessageObject, ArrayList entities, HashMap params) { if (peer == 0) { return; } @@ -855,7 +957,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else if (retryMessageObject.type == 3) { type = 3; - video = (TLRPC.TL_video) newMsg.media.video; + document = (TLRPC.TL_document) newMsg.media.document; } else if (retryMessageObject.type == 12) { user = new TLRPC.TL_userRequest_old2(); user.phone = newMsg.media.phone_number; @@ -871,7 +973,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter type = 7; } } else if (retryMessageObject.type == 2) { - audio = (TLRPC.TL_audio) newMsg.media.audio; + document = (TLRPC.TL_document) newMsg.media.document; type = 8; } } @@ -885,7 +987,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (entities != null && !entities.isEmpty()) { newMsg.entities = entities; } - if (encryptedChat != null || webPage == null) { + if (encryptedChat != null && webPage instanceof TLRPC.TL_webPagePending) { + if (webPage.url != null) { + TLRPC.WebPage newWebPage = new TLRPC.TL_webPageUrlPending(); + newWebPage.url = webPage.url; + webPage = newWebPage; + } else { + webPage = null; + } + } + if (webPage == null) { newMsg.media = new TLRPC.TL_messageMediaEmpty(); } else { newMsg.media = new TLRPC.TL_messageMediaWebPage(); @@ -927,22 +1038,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter TLRPC.FileLocation location1 = photo.sizes.get(photo.sizes.size() - 1).location; newMsg.attachPath = FileLoader.getPathToAttach(location1, true).toString(); } - } else if (video != null) { - if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { - newMsg = new TLRPC.TL_message_secret(); - } else { - newMsg = new TLRPC.TL_message(); - } - newMsg.media = new TLRPC.TL_messageMediaVideo(); - newMsg.media.caption = video.caption != null ? video.caption : ""; - newMsg.media.video = video; - type = 3; - if (videoEditedInfo == null) { - newMsg.message = "-1"; - } else { - newMsg.message = videoEditedInfo.getString(); - } - newMsg.attachPath = path; } else if (user != null) { if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { newMsg = new TLRPC.TL_message_secret(); @@ -971,24 +1066,25 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.media = new TLRPC.TL_messageMediaDocument(); newMsg.media.caption = document.caption != null ? document.caption : ""; newMsg.media.document = document; - if (params != null && params.containsKey("query_id")) { + if (MessageObject.isVideoDocument(document)) { + type = 3; + } else if (MessageObject.isVoiceDocument(document)) { + type = 8; + } else if (params != null && params.containsKey("query_id")) { type = 9; } else { type = 7; } - newMsg.message = "-1"; - newMsg.attachPath = path; - } else if (audio != null) { - if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { - newMsg = new TLRPC.TL_message_secret(); + if (videoEditedInfo == null) { + newMsg.message = "-1"; } else { - newMsg = new TLRPC.TL_message(); + newMsg.message = videoEditedInfo.getString(); + } + if (encryptedChat != null && document.dc_id > 0 && !MessageObject.isStickerDocument(document)) { + newMsg.attachPath = FileLoader.getPathToAttach(document).toString(); + } else { + newMsg.attachPath = path; } - newMsg.media = new TLRPC.TL_messageMediaAudio(); - newMsg.media.audio = audio; - type = 8; - newMsg.message = "-1"; - newMsg.attachPath = path; } if (newMsg.attachPath == null) { newMsg.attachPath = ""; @@ -1007,30 +1103,46 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.random_id = getNextRandomId(); } if (params != null && params.containsKey("bot")) { - newMsg.via_bot_id = Utilities.parseInt(params.get("bot")); + if (encryptedChat != null) { + newMsg.via_bot_name = params.get("bot_name"); + if (newMsg.via_bot_name == null) { + newMsg.via_bot_name = ""; + } + } else { + newMsg.via_bot_id = Utilities.parseInt(params.get("bot")); + } newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; } newMsg.params = params; newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; - if (encryptedChat == null && high_id != 1 && newMsg.media instanceof TLRPC.TL_messageMediaAudio) { - newMsg.media_unread = true; - } if (sendToPeer instanceof TLRPC.TL_inputPeerChannel) { if (asAdmin) { newMsg.views = 1; newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; } TLRPC.Chat chat = MessagesController.getInstance().getChat(sendToPeer.channel_id); - if (chat != null && chat.megagroup) { - newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + if (chat != null) { + if (chat.megagroup) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } else { + newMsg.post = true; + if (chat.signatures) { + newMsg.from_id = UserConfig.getClientUserId(); + } + } } } else { newMsg.unread = true; } newMsg.dialog_id = peer; if (reply_to_msg != null) { - newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; + if (encryptedChat != null && reply_to_msg.messageOwner.random_id != 0) { + newMsg.reply_to_random_id = reply_to_msg.messageOwner.random_id; + newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } else { + newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } newMsg.reply_to_msg_id = reply_to_msg.getId(); } if (lower_id != 0) { @@ -1073,13 +1185,32 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } newMsg.ttl = encryptedChat.ttl; if (newMsg.ttl != 0) { - if (newMsg.media instanceof TLRPC.TL_messageMediaAudio) { - newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.audio.duration + 1); - } else if (newMsg.media instanceof TLRPC.TL_messageMediaVideo) { - newMsg.ttl = Math.max(encryptedChat.ttl, newMsg.media.video.duration + 1); + if (MessageObject.isVoiceMessage(newMsg)) { + int duration = 0; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + newMsg.ttl = Math.max(encryptedChat.ttl, duration + 1); + } else if (MessageObject.isVideoMessage(newMsg)) { + int duration = 0; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } + newMsg.ttl = Math.max(encryptedChat.ttl, duration + 1); } } } + if ((encryptedChat == null || AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) && high_id != 1 && MessageObject.isVoiceMessage(newMsg) && newMsg.to_id.channel_id == 0) { + newMsg.media_unread = true; + } newMsgObj = new MessageObject(newMsg, null, true); newMsgObj.replyMessageObject = reply_to_msg; @@ -1093,7 +1224,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter MessagesController.getInstance().updateInterfaceWithMessages(peer, objArr); NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); - if (type == 0) { + if (type == 0 || type == 9 && message != null && encryptedChat != null) { if (encryptedChat == null) { if (sendToPeers != null) { TLRPC.TL_messages_sendBroadcast reqSend = new TLRPC.TL_messages_sendBroadcast(); @@ -1109,6 +1240,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { TLRPC.TL_messages_sendMessage reqSend = new TLRPC.TL_messages_sendMessage(); reqSend.message = message; + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } reqSend.peer = sendToPeer; reqSend.random_id = newMsg.random_id; if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { @@ -1125,20 +1259,41 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { TLRPC.TL_decryptedMessage reqSend; - if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { reqSend = new TLRPC.TL_decryptedMessage(); reqSend.ttl = newMsg.ttl; + if (entities != null && !entities.isEmpty()) { + reqSend.entities = entities; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + if (reply_to_msg != null && reply_to_msg.messageOwner.random_id != 0) { + reqSend.reply_to_random_id = reply_to_msg.messageOwner.random_id; + reqSend.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage_layer17(); + reqSend.ttl = newMsg.ttl; } else { - reqSend = new TLRPC.TL_decryptedMessage_old(); + reqSend = new TLRPC.TL_decryptedMessage_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } + if (params != null && params.get("bot_name") != null) { + reqSend.via_bot_name = params.get("bot_name"); + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } reqSend.random_id = newMsg.random_id; reqSend.message = message; - reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); + if (webPage != null && webPage.url != null) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaWebPage(); + reqSend.media.url = webPage.url; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); + } SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); } - } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8) { + } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8 || type == 9 && encryptedChat != null) { if (encryptedChat == null) { TLRPC.InputMedia inputMedia = null; DelayedMessage delayedMessage = null; @@ -1155,7 +1310,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter inputMedia.geo_point = new TLRPC.TL_inputGeoPoint(); inputMedia.geo_point.lat = location.geo.lat; inputMedia.geo_point._long = location.geo._long; - } else if (type == 2) { + } else if (type == 2 || type == 9 && photo != null) { if (photo.access_hash == 0) { inputMedia = new TLRPC.TL_inputMediaUploadedPhoto(); inputMedia.caption = photo.caption != null ? photo.caption : ""; @@ -1177,30 +1332,28 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter inputMedia = media; } } else if (type == 3) { - if (video.access_hash == 0) { - if (video.thumb.location != null) { - inputMedia = new TLRPC.TL_inputMediaUploadedThumbVideo(); + if (document.access_hash == 0) { + if (document.thumb.location != null) { + inputMedia = new TLRPC.TL_inputMediaUploadedThumbDocument(); } else { - inputMedia = new TLRPC.TL_inputMediaUploadedVideo(); + inputMedia = new TLRPC.TL_inputMediaUploadedDocument(); } - inputMedia.caption = video.caption != null ? video.caption : ""; - inputMedia.duration = video.duration; - inputMedia.w = video.w; - inputMedia.h = video.h; - inputMedia.mime_type = video.mime_type; + inputMedia.caption = document.caption != null ? document.caption : ""; + inputMedia.mime_type = document.mime_type; + inputMedia.attributes = document.attributes; delayedMessage = new DelayedMessage(); delayedMessage.originalPath = originalPath; delayedMessage.type = 1; delayedMessage.obj = newMsgObj; - delayedMessage.location = video.thumb.location; - delayedMessage.videoLocation = video; + delayedMessage.location = document.thumb.location; + delayedMessage.documentLocation = document; delayedMessage.videoEditedInfo = videoEditedInfo; } else { - TLRPC.TL_inputMediaVideo media = new TLRPC.TL_inputMediaVideo(); - media.id = new TLRPC.TL_inputVideo(); - media.caption = video.caption != null ? video.caption : ""; - media.id.id = video.id; - media.id.access_hash = video.access_hash; + TLRPC.TL_inputMediaDocument media = new TLRPC.TL_inputMediaDocument(); + media.id = new TLRPC.TL_inputDocument(); + media.caption = document.caption != null ? document.caption : ""; + media.id.id = document.id; + media.id.access_hash = document.access_hash; inputMedia = media; } } else if (type == 6) { @@ -1208,9 +1361,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter inputMedia.phone_number = user.phone; inputMedia.first_name = user.first_name; inputMedia.last_name = user.last_name; - } else if (type == 7) { + } else if (type == 7 || type == 9) { if (document.access_hash == 0) { - if (originalPath != null && originalPath.length() > 0 && originalPath.startsWith("http") && params != null) { + if (encryptedChat == null && originalPath != null && originalPath.length() > 0 && originalPath.startsWith("http") && params != null) { inputMedia = new TLRPC.TL_inputMediaGifExternal(); String args[] = params.get("url").split("\\|"); if (args.length == 2) { @@ -1242,19 +1395,21 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter inputMedia = media; } } else if (type == 8) { - if (audio.access_hash == 0) { - inputMedia = new TLRPC.TL_inputMediaUploadedAudio(); - inputMedia.duration = audio.duration; - inputMedia.mime_type = audio.mime_type; + if (document.access_hash == 0) { + inputMedia = new TLRPC.TL_inputMediaUploadedDocument(); + inputMedia.mime_type = document.mime_type; + inputMedia.attributes = document.attributes; + inputMedia.caption = document.caption != null ? document.caption : ""; delayedMessage = new DelayedMessage(); delayedMessage.type = 3; delayedMessage.obj = newMsgObj; - delayedMessage.audioLocation = audio; + delayedMessage.documentLocation = document; } else { - TLRPC.TL_inputMediaAudio media = new TLRPC.TL_inputMediaAudio(); - media.id = new TLRPC.TL_inputAudio(); - media.id.id = audio.id; - media.id.access_hash = audio.access_hash; + TLRPC.TL_inputMediaDocument media = new TLRPC.TL_inputMediaDocument(); + media.id = new TLRPC.TL_inputDocument(); + media.caption = document.caption != null ? document.caption : ""; + media.id.id = document.id; + media.id.access_hash = document.access_hash; inputMedia = media; } } @@ -1278,6 +1433,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { TLRPC.TL_messages_sendMedia request = new TLRPC.TL_messages_sendMedia(); request.peer = sendToPeer; + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + request.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } request.random_id = newMsg.random_id; request.media = inputMedia; if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { @@ -1301,7 +1459,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); } } else if (type == 3) { - if (video.access_hash == 0) { + if (document.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); @@ -1315,7 +1473,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter performSendMessageRequest(reqSend, newMsgObj.messageOwner, originalPath); } } else if (type == 8) { - if (audio.access_hash == 0) { + if (document.access_hash == 0) { performSendDelayedMessage(delayedMessage); } else { performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); @@ -1323,31 +1481,65 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { TLRPC.TL_decryptedMessage reqSend; - if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { reqSend = new TLRPC.TL_decryptedMessage(); reqSend.ttl = newMsg.ttl; + if (entities != null && !entities.isEmpty()) { + reqSend.entities = entities; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + if (reply_to_msg != null && reply_to_msg.messageOwner.random_id != 0) { + reqSend.reply_to_random_id = reply_to_msg.messageOwner.random_id; + reqSend.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage_layer17(); + reqSend.ttl = newMsg.ttl; } else { - reqSend = new TLRPC.TL_decryptedMessage_old(); + reqSend = new TLRPC.TL_decryptedMessage_layer8(); reqSend.random_bytes = new byte[15]; Utilities.random.nextBytes(reqSend.random_bytes); } + if (params != null && params.get("bot_name") != null) { + reqSend.via_bot_name = params.get("bot_name"); + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } reqSend.random_id = newMsg.random_id; reqSend.message = ""; if (type == 1) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); + if (location instanceof TLRPC.TL_messageMediaVenue && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVenue(); + reqSend.media.address = location.address; + reqSend.media.title = location.title; + reqSend.media.provider = location.provider; + reqSend.media.venue_id = location.venue_id; + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); + } reqSend.media.lat = location.geo.lat; reqSend.media._long = location.geo._long; SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); - } else if (type == 2) { + } else if (type == 2 || type == 9 && photo != null) { TLRPC.PhotoSize small = photo.sizes.get(0); TLRPC.PhotoSize big = photo.sizes.get(photo.sizes.size() - 1); - reqSend.media = new TLRPC.TL_decryptedMessageMediaPhoto(); - ImageLoader.fillPhotoSizeWithBytes(small); - if (small.bytes != null) { - ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = small.bytes; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaPhoto(); + reqSend.media.caption = photo.caption != null ? photo.caption : ""; + if (small.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = small.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = new byte[0]; + } } else { - ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = new byte[0]; + reqSend.media = new TLRPC.TL_decryptedMessageMediaPhoto_layer8(); + if (small.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaPhoto_layer8) reqSend.media).thumb = small.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaPhoto_layer8) reqSend.media).thumb = new byte[0]; + } } + ImageLoader.fillPhotoSizeWithBytes(small); reqSend.media.thumb_h = small.h; reqSend.media.thumb_w = small.w; reqSend.media.w = big.w; @@ -1375,45 +1567,59 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); } } else if (type == 3) { - ImageLoader.fillPhotoSizeWithBytes(video.thumb); - if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + ImageLoader.fillPhotoSizeWithBytes(document.thumb); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo(); - if (video.thumb != null && video.thumb.bytes != null) { - ((TLRPC.TL_decryptedMessageMediaVideo) reqSend.media).thumb = video.thumb.bytes; + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo) reqSend.media).thumb = document.thumb.bytes; } else { ((TLRPC.TL_decryptedMessageMediaVideo) reqSend.media).thumb = new byte[0]; } - } else { - reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_old(); - if (video.thumb != null && video.thumb.bytes != null) { - ((TLRPC.TL_decryptedMessageMediaVideo_old) reqSend.media).thumb = video.thumb.bytes; + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_layer17(); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo_layer17) reqSend.media).thumb = document.thumb.bytes; } else { - ((TLRPC.TL_decryptedMessageMediaVideo_old) reqSend.media).thumb = new byte[0]; + ((TLRPC.TL_decryptedMessageMediaVideo_layer17) reqSend.media).thumb = new byte[0]; + } + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_layer8(); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo_layer8) reqSend.media).thumb = document.thumb.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaVideo_layer8) reqSend.media).thumb = new byte[0]; } } - reqSend.media.duration = video.duration; - reqSend.media.size = video.size; - reqSend.media.w = video.w; - reqSend.media.h = video.h; - reqSend.media.thumb_h = video.thumb.h; - reqSend.media.thumb_w = video.thumb.w; + reqSend.media.caption = document.caption != null ? document.caption : ""; reqSend.media.mime_type = "video/mp4"; - if (video.access_hash == 0) { + reqSend.media.size = document.size; + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + reqSend.media.w = attribute.w; + reqSend.media.h = attribute.h; + reqSend.media.duration = attribute.duration; + break; + } + } + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + if (document.access_hash == 0) { DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.originalPath = originalPath; delayedMessage.sendEncryptedRequest = reqSend; delayedMessage.type = 1; delayedMessage.obj = newMsgObj; delayedMessage.encryptedChat = encryptedChat; - delayedMessage.videoLocation = video; + delayedMessage.documentLocation = document; delayedMessage.videoEditedInfo = videoEditedInfo; performSendDelayedMessage(delayedMessage); } else { TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); - encryptedFile.id = video.id; - encryptedFile.access_hash = video.access_hash; - reqSend.media.key = video.key; - reqSend.media.iv = video.iv; + encryptedFile.id = document.id; + encryptedFile.access_hash = document.access_hash; + reqSend.media.key = document.key; + reqSend.media.iv = document.iv; SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); } } else if (type == 6) { @@ -1423,14 +1629,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media.last_name = user.last_name; reqSend.media.user_id = user.id; SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); - } else if (type == 7) { - boolean isSticker = false; - for (TLRPC.DocumentAttribute attribute : document.attributes) { - if (attribute instanceof TLRPC.TL_documentAttributeSticker) { - isSticker = true; - } - } - if (isSticker) { + } else if (type == 7 || type == 9 && document != null) { + if (MessageObject.isStickerDocument(document)) { reqSend.media = new TLRPC.TL_decryptedMessageMediaExternalDocument(); reqSend.media.id = document.id; reqSend.media.date = document.date; @@ -1441,27 +1641,43 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.media.attributes = document.attributes; if (document.thumb == null) { ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb = new TLRPC.TL_photoSizeEmpty(); + ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb.type = "s"; } else { ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb = document.thumb; } SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); } else { ImageLoader.fillPhotoSizeWithBytes(document.thumb); - reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); - reqSend.media.size = document.size; - if (document.thumb != null && document.thumb.bytes != null) { - ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = document.thumb.bytes; - reqSend.media.thumb_h = document.thumb.h; - reqSend.media.thumb_w = document.thumb.w; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); + reqSend.media.attributes = document.attributes; + reqSend.media.caption = document.caption != null ? document.caption : ""; + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } } else { - ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = new byte[0]; - reqSend.media.thumb_h = 0; - reqSend.media.thumb_w = 0; + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument_layer8(); + reqSend.media.file_name = FileLoader.getDocumentFileName(document); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument_layer8) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument_layer8) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } } - reqSend.media.file_name = FileLoader.getDocumentFileName(document); + reqSend.media.size = document.size; reqSend.media.mime_type = document.mime_type; - if (document.access_hash == 0) { + if (document.key == null) { DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.originalPath = originalPath; delayedMessage.sendEncryptedRequest = reqSend; @@ -1483,21 +1699,46 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } } else if (type == 8) { - if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); - } else { - reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_old(); - } - reqSend.media.duration = audio.duration; - reqSend.media.size = audio.size; - reqSend.media.mime_type = "audio/ogg"; - DelayedMessage delayedMessage = new DelayedMessage(); - delayedMessage.sendEncryptedRequest = reqSend; - delayedMessage.type = 3; - delayedMessage.obj = newMsgObj; delayedMessage.encryptedChat = encryptedChat; - delayedMessage.audioLocation = audio; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.obj = newMsgObj; + delayedMessage.documentLocation = document; + delayedMessage.type = 3; + + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); + reqSend.media.attributes = document.attributes; + reqSend.media.caption = document.caption != null ? document.caption : ""; + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } + reqSend.media.mime_type = document.mime_type; + reqSend.media.size = document.size; + delayedMessage.originalPath = originalPath; + } else { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_layer8(); + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + reqSend.media.duration = attribute.duration; + break; + } + } + reqSend.media.mime_type = "audio/ogg"; + reqSend.media.size = document.size; + delayedMessage.type = 3; + } performSendDelayedMessage(delayedMessage); } } @@ -1509,6 +1750,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { reqSend.from_peer = new TLRPC.TL_inputPeerEmpty(); } + if (retryMessageObject.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } reqSend.random_id.add(newMsg.random_id); if (retryMessageObject.getId() >= 0) { reqSend.id.add(retryMessageObject.getId()); @@ -1530,6 +1774,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter reqSend.flags |= 1; reqSend.reply_to_msg_id = reply_to_msg.getId(); } + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } reqSend.query_id = Utilities.parseLong(params.get("query_id")); reqSend.id = params.get("id"); performSendMessageRequest(reqSend, newMsgObj.messageOwner, null); @@ -1563,7 +1810,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (message.videoEditedInfo != null) { String location = message.obj.messageOwner.attachPath; if (location == null) { - location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.videoLocation.id + ".mp4"; + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; } putToDelayedMessages(location, message); MediaController.getInstance().scheduleVideoConvert(message.obj); @@ -1578,11 +1825,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (media.file == null) { String location = message.obj.messageOwner.attachPath; if (location == null) { - location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.videoLocation.id + ".mp4"; + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; } putToDelayedMessages(location, message); if (message.obj.videoEditedInfo != null) { - FileLoader.getInstance().uploadFile(location, false, false, message.videoLocation.size); + FileLoader.getInstance().uploadFile(location, false, false, message.documentLocation.size); } else { FileLoader.getInstance().uploadFile(location, false, false); } @@ -1594,11 +1841,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { String location = message.obj.messageOwner.attachPath; if (location == null) { - location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.videoLocation.id + ".mp4"; + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; } putToDelayedMessages(location, message); if (message.obj.videoEditedInfo != null) { - FileLoader.getInstance().uploadFile(location, true, false, message.videoLocation.size); + FileLoader.getInstance().uploadFile(location, true, false, message.documentLocation.size); } else { FileLoader.getInstance().uploadFile(location, true, false); } @@ -1631,6 +1878,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } else { String location = message.obj.messageOwner.attachPath; + if (message.sendEncryptedRequest != null && message.documentLocation.dc_id != 0) { + File file = new File(location); + if (!file.exists()) { + putToDelayedMessages(FileLoader.getAttachFileName(message.documentLocation), message); + FileLoader.getInstance().loadFile(message.documentLocation, true, false); + return; + } + } putToDelayedMessages(location, message); FileLoader.getInstance().uploadFile(location, true, false); } @@ -1692,7 +1947,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsgObj.date = res.date; newMsgObj.entities = res.entities; newMsgObj.out = res.out; - newMsgObj.unread = res.unread; if (res.media != null) { newMsgObj.media = res.media; newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; @@ -1776,7 +2030,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter removeFromSendingMessages(oldId); } }); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + if (MessageObject.isVideoMessage(newMsgObj)) { stopVideoService(attachPath); } } @@ -1793,7 +2047,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); processSentMessage(newMsgObj.id); - if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { + if (MessageObject.isVideoMessage(newMsgObj)) { stopVideoService(newMsgObj.attachPath); } removeFromSendingMessages(newMsgObj.id); @@ -1862,39 +2116,13 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter sentMessage.attachPath = newMsg.attachPath; newMsg.media.photo.id = sentMessage.media.photo.id; newMsg.media.photo.access_hash = sentMessage.media.photo.access_hash; - } else if (sentMessage.media instanceof TLRPC.TL_messageMediaVideo && sentMessage.media.video != null && newMsg.media instanceof TLRPC.TL_messageMediaVideo && newMsg.media.video != null) { - MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.video, 2); - - TLRPC.PhotoSize size2 = newMsg.media.video.thumb; - TLRPC.PhotoSize size = sentMessage.media.video.thumb; - if (size2 != null && size2.location != null && size2.location.volume_id == Integer.MIN_VALUE && size != null && size.location != null && !(size instanceof TLRPC.TL_photoSizeEmpty) && !(size2 instanceof TLRPC.TL_photoSizeEmpty)) { - String fileName = size2.location.volume_id + "_" + size2.location.local_id; - String fileName2 = size.location.volume_id + "_" + size.location.local_id; - if (!fileName.equals(fileName2)) { - File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName + ".jpg"); - File cacheFile2 = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName2 + ".jpg"); - cacheFile.renameTo(cacheFile2); - ImageLoader.getInstance().replaceImageInCache(fileName, fileName2, size.location, post); - size2.location = size.location; - } - } - - sentMessage.message = newMsg.message; - newMsg.media.video.dc_id = sentMessage.media.video.dc_id; - newMsg.media.video.id = sentMessage.media.video.id; - newMsg.media.video.access_hash = sentMessage.media.video.access_hash; - - if (newMsg.attachPath != null && newMsg.attachPath.startsWith(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE).getAbsolutePath())) { - File cacheFile = new File(newMsg.attachPath); - File cacheFile2 = FileLoader.getPathToAttach(newMsg.media.video); - if (!cacheFile.renameTo(cacheFile2)) { - sentMessage.attachPath = newMsg.attachPath; - } - } else { - sentMessage.attachPath = newMsg.attachPath; - } } else if (sentMessage.media instanceof TLRPC.TL_messageMediaDocument && sentMessage.media.document != null && newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { - MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.document, 1); + if (MessageObject.isVideoMessage(sentMessage)) { + MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.document, 2); + sentMessage.attachPath = newMsg.attachPath; + } else if (!MessageObject.isVoiceMessage(sentMessage)) { + MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.document, 1); + } TLRPC.PhotoSize size2 = newMsg.media.document.thumb; TLRPC.PhotoSize size = sentMessage.media.document.thumb; @@ -1916,11 +2144,27 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter newMsg.media.document.dc_id = sentMessage.media.document.dc_id; newMsg.media.document.id = sentMessage.media.document.id; newMsg.media.document.access_hash = sentMessage.media.document.access_hash; + byte[] oldWaveform = null; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + oldWaveform = attribute.waveform; + } + } newMsg.media.document.attributes = sentMessage.media.document.attributes; + if (oldWaveform != null) { + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + attribute.waveform = oldWaveform; + attribute.flags |= 4; + } + } + } newMsg.media.document.size = sentMessage.media.document.size; newMsg.media.document.mime_type = sentMessage.media.document.mime_type; - if (MessageObject.isOut(sentMessage) && MessageObject.isNewGifDocument(sentMessage.media.document)) { + if ((sentMessage.flags & TLRPC.MESSAGE_FLAG_FWD) == 0 && MessageObject.isOut(sentMessage) && MessageObject.isNewGifDocument(sentMessage.media.document)) { MessagesController.addNewGifToRecent(sentMessage.media.document, sentMessage.date); } @@ -1930,7 +2174,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (!cacheFile.renameTo(cacheFile2)) { sentMessage.attachPath = newMsg.attachPath; sentMessage.message = newMsg.message; - } else { + } else if (!MessageObject.isVideoMessage(sentMessage)) { newMsg.attachPath = ""; if (originalPath != null && originalPath.startsWith("http")) { MessagesStorage.getInstance().addRecentLocalFile(originalPath, cacheFile2.toString(), newMsg.media.document); @@ -1940,21 +2184,6 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter sentMessage.attachPath = newMsg.attachPath; sentMessage.message = newMsg.message; } - } else if (sentMessage.media instanceof TLRPC.TL_messageMediaAudio && sentMessage.media.audio != null && newMsg.media instanceof TLRPC.TL_messageMediaAudio && newMsg.media.audio != null) { - sentMessage.message = newMsg.message; - - String fileName = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".ogg"; - newMsg.media.audio.dc_id = sentMessage.media.audio.dc_id; - newMsg.media.audio.id = sentMessage.media.audio.id; - newMsg.media.audio.access_hash = sentMessage.media.audio.access_hash; - String fileName2 = sentMessage.media.audio.dc_id + "_" + sentMessage.media.audio.id + ".ogg"; - if (!fileName.equals(fileName2)) { - File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); - File cacheFile2 = FileLoader.getPathToAttach(sentMessage.media.audio); - if (!cacheFile.renameTo(cacheFile2)) { - sentMessage.attachPath = newMsg.attachPath; - } - } } else if (sentMessage.media instanceof TLRPC.TL_messageMediaContact && newMsg.media instanceof TLRPC.TL_messageMediaContact) { newMsg.media = sentMessage.media; } else if (sentMessage.media instanceof TLRPC.TL_messageMediaWebPage) { @@ -1994,7 +2223,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter MessagesController.getInstance().putUsers(users, true); MessagesController.getInstance().putChats(chats, true); MessagesController.getInstance().putEncryptedChats(encryptedChats, true); - for (TLRPC.Message message : messages) { + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); MessageObject messageObject = new MessageObject(message, null, false); retrySendMessage(messageObject, true); } @@ -2030,7 +2260,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } - private static boolean prepareSendingDocumentInternal(String path, String originalPath, Uri uri, String mime, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + private static boolean prepareSendingDocumentInternal(String path, String originalPath, Uri uri, String mime, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin, String caption) { if ((path == null || path.length() == 0) && uri == null) { return false; } @@ -2067,7 +2297,16 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter AudioInfo audioInfo = AudioInfo.getAudioInfo(f); if (audioInfo != null && audioInfo.getDuration() != 0) { if (isEncrypted) { - attributeAudio = new TLRPC.TL_documentAttributeAudio_old(); + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return false; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + attributeAudio = new TLRPC.TL_documentAttributeAudio(); + } else { + attributeAudio = new TLRPC.TL_documentAttributeAudio_old(); + } } else { attributeAudio = new TLRPC.TL_documentAttributeAudio(); } @@ -2076,9 +2315,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter attributeAudio.performer = audioInfo.getArtist(); if (attributeAudio.title == null) { attributeAudio.title = ""; + attributeAudio.flags |= 1; } if (attributeAudio.performer == null) { attributeAudio.performer = ""; + attributeAudio.flags |= 2; } } } @@ -2149,7 +2390,18 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (bmOptions.outWidth != 0 && bmOptions.outHeight != 0 && bmOptions.outWidth <= 800 && bmOptions.outHeight <= 800) { TLRPC.TL_documentAttributeSticker attributeSticker; if (isEncrypted) { - attributeSticker = new TLRPC.TL_documentAttributeSticker_old(); + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return false; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + attributeSticker = new TLRPC.TL_documentAttributeSticker(); + attributeSticker.alt = ""; + attributeSticker.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } else { + attributeSticker = new TLRPC.TL_documentAttributeSticker_old(); + } } else { attributeSticker = new TLRPC.TL_documentAttributeSticker(); attributeSticker.alt = ""; @@ -2167,6 +2419,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter document.thumb.type = "s"; } } + document.caption = caption; final HashMap params = new HashMap<>(); if (originalPath != null) { @@ -2177,7 +2430,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { - SendMessagesHelper.getInstance().sendMessage(documentFinal, pathFinal, dialog_id, reply_to_msg, asAdmin, params); + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, asAdmin, params); } }); return true; @@ -2224,13 +2477,20 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } if (isEncrypted) { - for (int b = 0; b < document.attributes.size(); b++) { - if (document.attributes.get(b) instanceof TLRPC.TL_documentAttributeAudio) { - TLRPC.TL_documentAttributeAudio_old old = new TLRPC.TL_documentAttributeAudio_old(); - old.duration = document.attributes.get(b).duration; - document.attributes.remove(b); - document.attributes.add(old); - break; + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) < 46) { + for (int b = 0; b < document.attributes.size(); b++) { + if (document.attributes.get(b) instanceof TLRPC.TL_documentAttributeAudio) { + TLRPC.TL_documentAttributeAudio_old old = new TLRPC.TL_documentAttributeAudio_old(); + old.duration = document.attributes.get(b).duration; + document.attributes.remove(b); + document.attributes.add(old); + break; + } } } } @@ -2243,7 +2503,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { - SendMessagesHelper.getInstance().sendMessage(documentFinal, messageObject.messageOwner.attachPath, dialog_id, reply_to_msg, asAdmin, params); + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, messageObject.messageOwner.attachPath, dialog_id, reply_to_msg, asAdmin, params); } }); } @@ -2261,14 +2521,14 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter boolean error = false; if (paths != null) { for (int a = 0; a < paths.size(); a++) { - if (!prepareSendingDocumentInternal(paths.get(a), originalPaths.get(a), null, mime, dialog_id, reply_to_msg, asAdmin)) { + if (!prepareSendingDocumentInternal(paths.get(a), originalPaths.get(a), null, mime, dialog_id, reply_to_msg, asAdmin, null)) { error = true; } } } if (uris != null) { for (int a = 0; a < uris.size(); a++) { - if (!prepareSendingDocumentInternal(null, null, uris.get(a), mime, dialog_id, reply_to_msg, asAdmin)) { + if (!prepareSendingDocumentInternal(null, null, uris.get(a), mime, dialog_id, reply_to_msg, asAdmin, null)) { error = true; } } @@ -2335,7 +2595,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } else { if (result.content_url != null) { - finalPath = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.content_url) + "." + ImageLoader.getHttpUrlExtension(result.content_url)).getAbsolutePath(); + finalPath = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.content_url) + "." + ImageLoader.getHttpUrlExtension(result.content_url, "jpg")).getAbsolutePath(); if (result.type.equals("gif")){ document = new TLRPC.TL_document(); document.id = 0; @@ -2345,7 +2605,12 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter document.attributes.add(fileName); document.size = 0; document.dc_id = 0; - document.mime_type = "image/gif"; + if (finalPath.endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } try { Bitmap bitmap; if (finalPath.endsWith("mp4")) { @@ -2398,7 +2663,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter public void run() { if (finalDocument != null) { finalDocument.caption = result.send_message.caption; - SendMessagesHelper.getInstance().sendMessage(finalDocument, finalPathFinal, dialog_id, reply_to_msg, asAdmin, params); + SendMessagesHelper.getInstance().sendMessage(finalDocument, null, finalPathFinal, dialog_id, reply_to_msg, asAdmin, params); } else if (finalPhoto != null) { finalPhoto.caption = result.send_message.caption; SendMessagesHelper.getInstance().sendMessage(finalPhoto, result.content_url, dialog_id, reply_to_msg, asAdmin, params); @@ -2436,7 +2701,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter document = (TLRPC.TL_document) doc; } } - String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl); + String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); } if (document == null) { @@ -2452,14 +2717,19 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter document.attributes.add(fileName); document.size = searchImage.size; document.dc_id = 0; - document.mime_type = "image/gif"; + if (cacheFile.toString().endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } if (cacheFile.exists()) { thumbFile = cacheFile; } else { cacheFile = null; } if (thumbFile == null) { - String thumb = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl); + String thumb = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl, "jpg"); thumbFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), thumb); if (!thumbFile.exists()) { thumbFile = null; @@ -2503,7 +2773,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { - SendMessagesHelper.getInstance().sendMessage(documentFinal, pathFinal, dialog_id, reply_to_msg, asAdmin, params); + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, asAdmin, params); } }); } else { @@ -2513,7 +2783,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter photo = (TLRPC.TL_photo) MessagesStorage.getInstance().getSentFile(searchImage.imageUrl, !isEncrypted ? 0 : 3); } if (photo == null) { - String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl); + String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); if (cacheFile.exists() && cacheFile.length() != 0) { photo = SendMessagesHelper.getInstance().generatePhotoSizes(cacheFile.toString(), null); @@ -2522,7 +2792,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } if (photo == null) { - md5 = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl); + md5 = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl, "jpg"); cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); if (cacheFile.exists()) { photo = SendMessagesHelper.getInstance().generatePhotoSizes(cacheFile.toString(), null); @@ -2622,6 +2892,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter ArrayList sendAsDocuments = null; ArrayList sendAsDocumentsOriginal = null; + ArrayList sendAsDocumentsCaptions = null; int count = !pathsCopy.isEmpty() ? pathsCopy.size() : urisCopy.size(); String path = null; Uri uri = null; @@ -2666,9 +2937,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter if (sendAsDocuments == null) { sendAsDocuments = new ArrayList<>(); sendAsDocumentsOriginal = new ArrayList<>(); + sendAsDocumentsCaptions = new ArrayList<>(); } sendAsDocuments.add(tempPath); sendAsDocumentsOriginal.add(originalPath); + sendAsDocumentsCaptions.add(captions != null ? captions.get(a) : null); } else { if (tempPath != null) { File temp = new File(tempPath); @@ -2706,7 +2979,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { for (int a = 0; a < sendAsDocuments.size(); a++) { - prepareSendingDocumentInternal(sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), null, extension, dialog_id, reply_to_msg, asAdmin); + prepareSendingDocumentInternal(sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), null, extension, dialog_id, reply_to_msg, asAdmin, sendAsDocumentsCaptions.get(a)); } } } @@ -2734,35 +3007,36 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter originalPath += "_" + videoEditedInfo.resultWidth; } } - TLRPC.TL_video video = null; + TLRPC.TL_document document = null; if (!isEncrypted) { - video = (TLRPC.TL_video) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5); + TLObject object = MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5); + document = (TLRPC.TL_document) object; } - if (video == null) { + if (document == null) { Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); - video = new TLRPC.TL_video(); - video.thumb = size; - if (video.thumb == null) { - video.thumb = new TLRPC.TL_photoSizeEmpty(); - video.thumb.type = "s"; + document = new TLRPC.TL_document(); + document.thumb = size; + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; } else { - video.thumb.type = "s"; + document.thumb.type = "s"; } - video.mime_type = "video/mp4"; - video.id = 0; + document.mime_type = "video/mp4"; UserConfig.saveConfig(false); - + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + document.attributes.add(attributeVideo); if (videoEditedInfo != null) { - video.duration = (int) (duration / 1000); + attributeVideo.duration = (int) (duration / 1000); if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { - video.w = height; - video.h = width; + attributeVideo.w = height; + attributeVideo.h = width; } else { - video.w = width; - video.h = height; + attributeVideo.w = width; + attributeVideo.h = height; } - video.size = (int) estimatedSize; + document.size = (int) estimatedSize; String fileName = Integer.MIN_VALUE + "_" + UserConfig.lastLocalId + ".mp4"; UserConfig.lastLocalId--; File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); @@ -2770,7 +3044,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter path = cacheFile.getAbsolutePath(); } else { if (temp.exists()) { - video.size = (int) temp.length(); + document.size = (int) temp.length(); } boolean infoObtained = false; if (Build.VERSION.SDK_INT >= 14) { @@ -2780,15 +3054,15 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter mediaMetadataRetriever.setDataSource(videoPath); String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); if (width != null) { - video.w = Integer.parseInt(width); + attributeVideo.w = Integer.parseInt(width); } String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); if (height != null) { - video.h = Integer.parseInt(height); + attributeVideo.h = Integer.parseInt(height); } String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); if (duration != null) { - video.duration = (int) Math.ceil(Long.parseLong(duration) / 1000.0f); + attributeVideo.duration = (int) Math.ceil(Long.parseLong(duration) / 1000.0f); } infoObtained = true; } catch (Exception e) { @@ -2807,9 +3081,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter try { MediaPlayer mp = MediaPlayer.create(ApplicationLoader.applicationContext, Uri.fromFile(new File(videoPath))); if (mp != null) { - video.duration = (int) Math.ceil(mp.getDuration() / 1000.0f); - video.w = mp.getVideoWidth(); - video.h = mp.getVideoHeight(); + attributeVideo.duration = (int) Math.ceil(mp.getDuration() / 1000.0f); + attributeVideo.w = mp.getVideoWidth(); + attributeVideo.h = mp.getVideoHeight(); mp.release(); } } catch (Exception e) { @@ -2818,7 +3092,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } } } - final TLRPC.TL_video videoFinal = video; + final TLRPC.TL_document videoFinal = document; final String originalPathFinal = originalPath; final String finalPath = path; final HashMap params = new HashMap<>(); @@ -2832,7 +3106,7 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter } }); } else { - prepareSendingDocumentInternal(videoPath, videoPath, null, null, dialog_id, reply_to_msg, asAdmin); + prepareSendingDocumentInternal(videoPath, videoPath, null, null, dialog_id, reply_to_msg, asAdmin, null); } } }).start(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 6cda1ba7d..ea10ee13e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -39,7 +39,7 @@ public class UserConfig { public static int lastPauseTime = 0; public static boolean isWaitingForPasscodeEnter = false; public static boolean useFingerprint = true; - public static int lastUpdateVersion; + public static String lastUpdateVersion; public static int lastContactsSyncTime; public static int migrateOffsetId = -1; @@ -83,7 +83,7 @@ public class UserConfig { editor.putInt("passcodeType", passcodeType); editor.putInt("autoLockIn", autoLockIn); editor.putInt("lastPauseTime", lastPauseTime); - editor.putInt("lastUpdateVersion", lastUpdateVersion); + editor.putString("lastUpdateVersion2", lastUpdateVersion); editor.putInt("lastContactsSyncTime", lastContactsSyncTime); editor.putBoolean("useFingerprint", useFingerprint); @@ -224,7 +224,7 @@ public class UserConfig { autoLockIn = preferences.getInt("autoLockIn", 60 * 60); lastPauseTime = preferences.getInt("lastPauseTime", 0); useFingerprint = preferences.getBoolean("useFingerprint", true); - lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511); + lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5"); lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60); migrateOffsetId = preferences.getInt("migrateOffsetId", 0); @@ -314,7 +314,7 @@ public class UserConfig { lastPauseTime = 0; useFingerprint = true; isWaitingForPasscodeEnter = false; - lastUpdateVersion = BuildVars.BUILD_VERSION; + lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60; saveConfig(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index a1019ba34..694180579 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -53,6 +53,7 @@ public class Utilities { public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin); public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap); private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length); + public native static String readlink(String path); public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) { aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java index 28f5e113a..4ea6b8862 100755 --- a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java @@ -156,7 +156,7 @@ public class ID3v2Info extends AudioInfo { smallCover = cover; } } - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); } coverPictureType = picture.type; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java index d4014a780..551327785 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java @@ -60,6 +60,9 @@ public class MessagesSearchQuery { lastReturnedNum--; return; } + if (searchResultMessages.isEmpty()) { + return; + } query = lastSearchQuery; MessageObject messageObject = searchResultMessages.get(searchResultMessages.size() - 1); if (messageObject.getDialogId() == dialog_id && !messagesSearchEndReached[0]) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/ReplyMessageQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/ReplyMessageQuery.java index 2fea1da49..4ef51007c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/query/ReplyMessageQuery.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/ReplyMessageQuery.java @@ -32,111 +32,188 @@ import java.util.Locale; public class ReplyMessageQuery { public static void loadReplyMessagesForMessages(final ArrayList messages, final long dialog_id) { - final ArrayList replyMessages = new ArrayList<>(); - final HashMap> replyMessageOwners = new HashMap<>(); - final StringBuilder stringBuilder = new StringBuilder(); - int channelId = 0; - for (MessageObject messageObject : messages) { - if (messageObject.getId() > 0 && messageObject.isReply() && messageObject.replyMessageObject == null) { - Integer id = messageObject.messageOwner.reply_to_msg_id; - long messageId = id; - if (messageObject.messageOwner.to_id.channel_id != 0) { - messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; - channelId = messageObject.messageOwner.to_id.channel_id; - } - if (stringBuilder.length() > 0) { - stringBuilder.append(','); - } - stringBuilder.append(messageId); - ArrayList messageObjects = replyMessageOwners.get(id); - if (messageObjects == null) { - messageObjects = new ArrayList<>(); - replyMessageOwners.put(id, messageObjects); - } - messageObjects.add(messageObject); - if (!replyMessages.contains(id)) { - replyMessages.add(id); + if ((int) dialog_id == 0) { + final ArrayList replyMessages = new ArrayList<>(); + final HashMap> replyMessageRandomOwners = new HashMap<>(); + final StringBuilder stringBuilder = new StringBuilder(); + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject.isReply() && messageObject.replyMessageObject == null) { + Long id = messageObject.messageOwner.reply_to_random_id; + if (stringBuilder.length() > 0) { + stringBuilder.append(','); + } + stringBuilder.append(id); + ArrayList messageObjects = replyMessageRandomOwners.get(id); + if (messageObjects == null) { + messageObjects = new ArrayList<>(); + replyMessageRandomOwners.put(id, messageObjects); + } + messageObjects.add(messageObject); + if (!replyMessages.contains(id)) { + replyMessages.add(id); + } } } - } - if (replyMessages.isEmpty()) { - return; - } + if (replyMessages.isEmpty()) { + return; + } - final int channelIdFinal = channelId; - MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { - @Override - public void run() { - try { - final ArrayList result = new ArrayList<>(); - final ArrayList users = new ArrayList<>(); - final ArrayList chats = new ArrayList<>(); - ArrayList usersToLoad = new ArrayList<>(); - ArrayList chatsToLoad = new ArrayList<>(); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialog_id; - SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", stringBuilder.toString())); - while (cursor.next()) { - NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); - if (data != null && cursor.byteBufferValue(0, data) != 0) { - TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); - message.id = cursor.intValue(1); - message.date = cursor.intValue(2); - message.dialog_id = dialog_id; - MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); - result.add(message); - replyMessages.remove((Integer) message.id); - } - data.reuse(); - } - cursor.dispose(); - if (!usersToLoad.isEmpty()) { - MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users); - } - if (!chatsToLoad.isEmpty()) { - MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); - } - broadcastReplyMessages(result, replyMessageOwners, users, chats, dialog_id, true); - - if (!replyMessages.isEmpty()) { - if (channelIdFinal != 0) { - final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); - req.channel = MessagesController.getInputChannel(channelIdFinal); - req.id = replyMessages; - ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; - ImageLoader.saveMessagesThumbs(messagesRes.messages); - broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false); - MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); - saveReplyMessages(replyMessageOwners, messagesRes.messages); + ArrayList arrayList = replyMessageRandomOwners.remove(cursor.longValue(3)); + if (arrayList != null) { + MessageObject messageObject = new MessageObject(message, null, null, false); + for (int b = 0; b < arrayList.size(); b++) { + MessageObject object = arrayList.get(b); + object.replyMessageObject = messageObject; + object.messageOwner.reply_to_msg_id = messageObject.getId(); } } - }); - } else { - TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); - req.id = replyMessages; - ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; - ImageLoader.saveMessagesThumbs(messagesRes.messages); - broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false); - MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); - saveReplyMessages(replyMessageOwners, messagesRes.messages); - } - } - }); + } + data.reuse(); } + cursor.dispose(); + if (!replyMessageRandomOwners.isEmpty()) { + for (HashMap.Entry> entry : replyMessageRandomOwners.entrySet()) { + ArrayList arrayList = entry.getValue(); + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.reply_to_random_id = 0; + } + } + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialog_id); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + + } else { + final ArrayList replyMessages = new ArrayList<>(); + final HashMap> replyMessageOwners = new HashMap<>(); + final StringBuilder stringBuilder = new StringBuilder(); + int channelId = 0; + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject.getId() > 0 && messageObject.isReply() && messageObject.replyMessageObject == null) { + Integer id = messageObject.messageOwner.reply_to_msg_id; + long messageId = id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + channelId = messageObject.messageOwner.to_id.channel_id; + } + if (stringBuilder.length() > 0) { + stringBuilder.append(','); + } + stringBuilder.append(messageId); + ArrayList messageObjects = replyMessageOwners.get(id); + if (messageObjects == null) { + messageObjects = new ArrayList<>(); + replyMessageOwners.put(id, messageObjects); + } + messageObjects.add(messageObject); + if (!replyMessages.contains(id)) { + replyMessages.add(id); } - } catch (Exception e) { - FileLog.e("tmessages", e); } } - }); + if (replyMessages.isEmpty()) { + return; + } + + final int channelIdFinal = channelId; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + final ArrayList result = new ArrayList<>(); + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", stringBuilder.toString())); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialog_id; + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + result.add(message); + replyMessages.remove((Integer) message.id); + } + data.reuse(); + } + cursor.dispose(); + + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + broadcastReplyMessages(result, replyMessageOwners, users, chats, dialog_id, true); + + if (!replyMessages.isEmpty()) { + if (channelIdFinal != 0) { + final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); + req.channel = MessagesController.getInputChannel(channelIdFinal); + req.id = replyMessages; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false); + MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages); + } + } + }); + } else { + TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); + req.id = replyMessages; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialog_id, false); + MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages); + } + } + }); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } } private static void saveReplyMessages(final HashMap> replyMessageOwners, final ArrayList result) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java index d02912767..ee2a33f4c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java @@ -56,11 +56,11 @@ public class SharedMediaQuery { } else if (type == MEDIA_FILE) { req.filter = new TLRPC.TL_inputMessagesFilterDocument(); } else if (type == MEDIA_AUDIO) { - req.filter = new TLRPC.TL_inputMessagesFilterAudio(); + req.filter = new TLRPC.TL_inputMessagesFilterVoice(); } else if (type == MEDIA_URL) { req.filter = new TLRPC.TL_inputMessagesFilterUrl(); } else if (type == MEDIA_MUSIC) { - req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments(); + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); } req.q = ""; req.peer = MessagesController.getInputPeer(lower_part); @@ -101,11 +101,11 @@ public class SharedMediaQuery { } else if (type == MEDIA_FILE) { req.filter = new TLRPC.TL_inputMessagesFilterDocument(); } else if (type == MEDIA_AUDIO) { - req.filter = new TLRPC.TL_inputMessagesFilterAudio(); + req.filter = new TLRPC.TL_inputMessagesFilterVoice(); } else if (type == MEDIA_URL) { req.filter = new TLRPC.TL_inputMessagesFilterUrl(); } else if (type == MEDIA_MUSIC) { - req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments(); + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); } req.q = ""; req.peer = MessagesController.getInputPeer(lower_part); @@ -144,8 +144,10 @@ public class SharedMediaQuery { if (message == null) { return -1; } - if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaVideo) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) { return MEDIA_PHOTOVIDEO; + } else if (MessageObject.isVoiceMessage(message)) { + return MEDIA_AUDIO; } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { if (MessageObject.isStickerMessage(message)) { return -1; @@ -154,8 +156,6 @@ public class SharedMediaQuery { } else { return MEDIA_FILE; } - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - return MEDIA_AUDIO; } else if (!message.entities.isEmpty()) { for (int a = 0; a < message.entities.size(); a++) { TLRPC.MessageEntity entity = message.entities.get(a); @@ -171,9 +171,7 @@ public class SharedMediaQuery { if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { return false; } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || - message.media instanceof TLRPC.TL_messageMediaVideo || - message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isGifDocument(message.media.document) || - message.media instanceof TLRPC.TL_messageMediaAudio) { + message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isGifDocument(message.media.document)) { return true; } else if (!message.entities.isEmpty()) { for (int a = 0; a < message.entities.size(); a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java index cbf933072..c20586648 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java @@ -43,6 +43,7 @@ public class StickersQuery { private static int loadDate; private static ArrayList stickerSets = new ArrayList<>(); private static HashMap stickerSetsById = new HashMap<>(); + private static HashMap stickerSetsByName = new HashMap<>(); private static HashMap stickersByEmoji = new HashMap<>(); private static HashMap stickersById = new HashMap<>(); private static HashMap> allStickers = new HashMap<>(); @@ -57,6 +58,7 @@ public class StickersQuery { stickerSets.clear(); stickersByEmoji.clear(); stickerSetsById.clear(); + stickerSetsByName.clear(); loadingStickers = false; stickersLoaded = false; } @@ -95,6 +97,10 @@ public class StickersQuery { return stickerSetsById.containsKey(id); } + public static boolean isStickerPackInstalled(String name) { + return stickerSetsByName.containsKey(name); + } + public static String getEmojiForSticker(long id) { String value = stickersByEmoji.get(id); return value != null ? value : ""; @@ -124,32 +130,34 @@ public class StickersQuery { } public static void addNewStickerSet(final TLRPC.TL_messages_stickerSet set) { - if (!stickerSetsById.containsKey(set.set.id)) { - stickerSets.add(0, set); - stickerSetsById.put(set.set.id, set); - for (int a = 0; a < set.documents.size(); a++) { - TLRPC.Document document = set.documents.get(a); - stickersById.put(document.id, document); - } - for (int a = 0; a < set.packs.size(); a++) { - TLRPC.TL_stickerPack stickerPack = set.packs.get(a); - stickerPack.emoticon = stickerPack.emoticon.replace("\uFE0F", ""); - ArrayList arrayList = allStickers.get(stickerPack.emoticon); - if (arrayList == null) { - arrayList = new ArrayList<>(); - allStickers.put(stickerPack.emoticon, arrayList); - } - for (int c = 0; c < stickerPack.documents.size(); c++) { - Long id = stickerPack.documents.get(c); - if (!stickersByEmoji.containsKey(id)) { - stickersByEmoji.put(id, stickerPack.emoticon); - } - arrayList.add(stickersById.get(id)); - } - } - loadHash = calcStickersHash(stickerSets); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + if (stickerSetsById.containsKey(set.set.id) || stickerSetsByName.containsKey(set.set.short_name)) { + return; } + stickerSets.add(0, set); + stickerSetsById.put(set.set.id, set); + stickerSetsByName.put(set.set.short_name, set); + for (int a = 0; a < set.documents.size(); a++) { + TLRPC.Document document = set.documents.get(a); + stickersById.put(document.id, document); + } + for (int a = 0; a < set.packs.size(); a++) { + TLRPC.TL_stickerPack stickerPack = set.packs.get(a); + stickerPack.emoticon = stickerPack.emoticon.replace("\uFE0F", ""); + ArrayList arrayList = allStickers.get(stickerPack.emoticon); + if (arrayList == null) { + arrayList = new ArrayList<>(); + allStickers.put(stickerPack.emoticon, arrayList); + } + for (int c = 0; c < stickerPack.documents.size(); c++) { + Long id = stickerPack.documents.get(c); + if (!stickersByEmoji.containsKey(id)) { + stickersByEmoji.put(id, stickerPack.emoticon); + } + arrayList.add(stickersById.get(id)); + } + } + loadHash = calcStickersHash(stickerSets); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); StickersQuery.loadStickers(false, true); } @@ -258,22 +266,23 @@ public class StickersQuery { } } - private static void putStickersToCache(final ArrayList stickers, final int date, final int hash) { + private static void putStickersToCache(ArrayList stickers, final int date, final int hash) { + final ArrayList stickersFinal = stickers != null ? new ArrayList<>(stickers) : null; MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { @Override public void run() { try { - if (stickers != null) { + if (stickersFinal != null) { SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO stickers_v2 VALUES(?, ?, ?, ?)"); state.requery(); int size = 4; - for (int a = 0; a < stickers.size(); a++) { - size += stickers.get(a).getObjectSize(); + for (int a = 0; a < stickersFinal.size(); a++) { + size += stickersFinal.get(a).getObjectSize(); } NativeByteBuffer data = new NativeByteBuffer(size); - data.writeInt32(stickers.size()); - for (int a = 0; a < stickers.size(); a++) { - stickers.get(a).serializeToStream(data); + data.writeInt32(stickersFinal.size()); + for (int a = 0; a < stickersFinal.size(); a++) { + stickersFinal.get(a).serializeToStream(data); } state.bindInteger(1, 1); state.bindByteBuffer(2, data); @@ -296,6 +305,11 @@ public class StickersQuery { }); } + public static String getStickerSetName(long setId) { + TLRPC.TL_messages_stickerSet stickerSet = stickerSetsById.get(setId); + return stickerSet != null ? stickerSet.set.short_name : null; + } + public static long getStickerSetId(TLRPC.Document document) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); @@ -350,6 +364,7 @@ public class StickersQuery { try { final ArrayList stickerSetsNew = new ArrayList<>(); final HashMap stickerSetsByIdNew = new HashMap<>(); + final HashMap stickerSetsByNameNew = new HashMap<>(); final HashMap stickersByEmojiNew = new HashMap<>(); final HashMap stickersByIdNew = new HashMap<>(); final HashMap> allStickersNew = new HashMap<>(); @@ -361,6 +376,7 @@ public class StickersQuery { } stickerSetsNew.add(stickerSet); stickerSetsByIdNew.put(stickerSet.set.id, stickerSet); + stickerSetsByNameNew.put(stickerSet.set.short_name, stickerSet); for (int b = 0; b < stickerSet.documents.size(); b++) { TLRPC.Document document = stickerSet.documents.get(b); @@ -400,6 +416,7 @@ public class StickersQuery { public void run() { stickersById = stickersByIdNew; stickerSetsById = stickerSetsByIdNew; + stickerSetsByName = stickerSetsByNameNew; stickerSets = stickerSetsNew; allStickers = allStickersNew; stickersByEmoji = stickersByEmojiNew; @@ -469,7 +486,11 @@ public class StickersQuery { if (error == null) { Toast.makeText(fragment.getParentActivity(), LocaleController.getString("AddStickersInstalled", R.string.AddStickersInstalled), Toast.LENGTH_SHORT).show(); } else { - Toast.makeText(fragment.getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + if (error.text.equals("STICKERSETS_TOO_MUCH")) { + Toast.makeText(fragment.getParentActivity(), LocaleController.getString("TooMuchStickersets", R.string.TooMuchStickersets), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(fragment.getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + } } } loadStickers(false, true); @@ -539,6 +560,7 @@ public class StickersQuery { } } loadHash = calcStickersHash(stickerSets); + putStickersToCache(stickerSets, loadDate, loadHash); NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet(); req.stickerset = stickerSetID; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 79a94952d..8b6cf27d6 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -120,42 +120,46 @@ public class ConnectionsManager { @Override public void run() { FileLog.d("tmessages", "send request " + object + " with token = " + requestToken); - NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize()); - object.serializeToStream(buffer); - object.freeResources(); + try { + NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize()); + object.serializeToStream(buffer); + object.freeResources(); - native_sendRequest(buffer.address, new RequestDelegateInternal() { - @Override - public void run(int response, int errorCode, String errorText) { - try { - TLObject resp = null; - TLRPC.TL_error error = null; - if (response != 0) { - NativeByteBuffer buff = NativeByteBuffer.wrap(response); - resp = object.deserializeResponse(buff, buff.readInt32(true), true); - } else if (errorText != null) { - error = new TLRPC.TL_error(); - error.code = errorCode; - error.text = errorText; - FileLog.e("tmessages", object + " got error " + error.code + " " + error.text); - } - FileLog.d("tmessages", "java received " + resp + " error = " + error); - final TLObject finalResponse = resp; - final TLRPC.TL_error finalError = error; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - onComplete.run(finalResponse, finalError); - if (finalResponse != null) { - finalResponse.freeResources(); - } + native_sendRequest(buffer.address, new RequestDelegateInternal() { + @Override + public void run(int response, int errorCode, String errorText) { + try { + TLObject resp = null; + TLRPC.TL_error error = null; + if (response != 0) { + NativeByteBuffer buff = NativeByteBuffer.wrap(response); + resp = object.deserializeResponse(buff, buff.readInt32(true), true); + } else if (errorText != null) { + error = new TLRPC.TL_error(); + error.code = errorCode; + error.text = errorText; + FileLog.e("tmessages", object + " got error " + error.code + " " + error.text); } - }); - } catch (Exception e) { - FileLog.e("tmessages", e); + FileLog.d("tmessages", "java received " + resp + " error = " + error); + final TLObject finalResponse = resp; + final TLRPC.TL_error finalError = error; + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + onComplete.run(finalResponse, finalError); + if (finalResponse != null) { + finalResponse.freeResources(); + } + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } - } - }, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken); + }, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } }); return requestToken; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java b/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java index b8b76ed28..eddea361a 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java @@ -40,13 +40,17 @@ public class NativeByteBuffer extends AbstractSerializedData { } - public NativeByteBuffer(int size) { - address = native_getFreeBuffer(size); - if (address != 0) { - buffer = native_getJavaByteBuffer(address); - buffer.position(0); - buffer.limit(size); - buffer.order(ByteOrder.LITTLE_ENDIAN); + public NativeByteBuffer(int size) throws Exception { + if (size >= 0) { + address = native_getFreeBuffer(size); + if (address != 0) { + buffer = native_getJavaByteBuffer(address); + buffer.position(0); + buffer.limit(size); + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + } else { + throw new Exception("invalid NativeByteBuffer size"); } } diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java index a6c063ca3..11e79f95e 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java @@ -23,11 +23,12 @@ public class TLClassStore { classStore.put(TLRPC.TL_decryptedMessage.constructor, TLRPC.TL_decryptedMessage.class); classStore.put(TLRPC.TL_config.constructor, TLRPC.TL_config.class); classStore.put(TLRPC.TL_decryptedMessageLayer.constructor, TLRPC.TL_decryptedMessageLayer.class); - classStore.put(TLRPC.TL_decryptedMessageService_old.constructor, TLRPC.TL_decryptedMessageService_old.class); - classStore.put(TLRPC.TL_decryptedMessage_old.constructor, TLRPC.TL_decryptedMessage_old.class); + classStore.put(TLRPC.TL_decryptedMessage_layer17.constructor, TLRPC.TL_decryptedMessage.class); + classStore.put(TLRPC.TL_decryptedMessageService_layer8.constructor, TLRPC.TL_decryptedMessageService_layer8.class); + classStore.put(TLRPC.TL_decryptedMessage_layer8.constructor, TLRPC.TL_decryptedMessage_layer8.class); classStore.put(TLRPC.TL_message_secret.constructor, TLRPC.TL_message_secret.class); + classStore.put(TLRPC.TL_message_secret_old.constructor, TLRPC.TL_message_secret_old.class); classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class); - classStore.put(TLRPC.TL_decryptedMessageHolder.constructor, TLRPC.TL_decryptedMessageHolder.class); classStore.put(TLRPC.TL_null.constructor, TLRPC.TL_null.class); classStore.put(TLRPC.TL_updateShortChatMessage.constructor, TLRPC.TL_updateShortChatMessage.class); @@ -37,33 +38,6 @@ public class TLClassStore { classStore.put(TLRPC.TL_updatesCombined.constructor, TLRPC.TL_updatesCombined.class); classStore.put(TLRPC.TL_updateShortSentMessage.constructor, TLRPC.TL_updateShortSentMessage.class); classStore.put(TLRPC.TL_updatesTooLong.constructor, TLRPC.TL_updatesTooLong.class); - - classStore.put(TLRPC.TL_video.constructor, TLRPC.TL_video.class); - classStore.put(TLRPC.TL_videoEmpty.constructor, TLRPC.TL_videoEmpty.class); - classStore.put(TLRPC.TL_video_old2.constructor, TLRPC.TL_video_old2.class); - classStore.put(TLRPC.TL_video_old.constructor, TLRPC.TL_video_old.class); - classStore.put(TLRPC.TL_videoEncrypted.constructor, TLRPC.TL_videoEncrypted.class); - classStore.put(TLRPC.TL_video_old3.constructor, TLRPC.TL_video_old3.class); - - classStore.put(TLRPC.TL_audio.constructor, TLRPC.TL_audio.class); - classStore.put(TLRPC.TL_audioEncrypted.constructor, TLRPC.TL_audioEncrypted.class); - classStore.put(TLRPC.TL_audioEmpty.constructor, TLRPC.TL_audioEmpty.class); - classStore.put(TLRPC.TL_audio_old.constructor, TLRPC.TL_audio_old.class); - classStore.put(TLRPC.TL_audio_old2.constructor, TLRPC.TL_audio_old2.class); - - classStore.put(TLRPC.TL_document.constructor, TLRPC.TL_document.class); - classStore.put(TLRPC.TL_documentEmpty.constructor, TLRPC.TL_documentEmpty.class); - classStore.put(TLRPC.TL_documentEncrypted_old.constructor, TLRPC.TL_documentEncrypted_old.class); - classStore.put(TLRPC.TL_documentEncrypted.constructor, TLRPC.TL_documentEncrypted.class); - classStore.put(TLRPC.TL_document_old.constructor, TLRPC.TL_document_old.class); - - classStore.put(TLRPC.TL_photo.constructor, TLRPC.TL_photo.class); - classStore.put(TLRPC.TL_photoEmpty.constructor, TLRPC.TL_photoEmpty.class); - classStore.put(TLRPC.TL_photoSize.constructor, TLRPC.TL_photoSize.class); - classStore.put(TLRPC.TL_photoSizeEmpty.constructor, TLRPC.TL_photoSizeEmpty.class); - classStore.put(TLRPC.TL_photoCachedSize.constructor, TLRPC.TL_photoCachedSize.class); - classStore.put(TLRPC.TL_photo_old.constructor, TLRPC.TL_photo_old.class); - classStore.put(TLRPC.TL_photo_old2.constructor, TLRPC.TL_photo_old2.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index 00b74beed..ee31d06b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -56,7 +56,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; public static final int MESSAGE_FLAG_MEGAGROUP = 0x80000000; - public static final int LAYER = 45; + public static final int LAYER = 48; public static class ChatPhoto extends TLObject { public FileLocation photo_small; @@ -424,8 +424,11 @@ public class TLRPC { public int duration; public String alt; public InputStickerSet stickerset; + public int flags; + public boolean voice; public String title; public String performer; + public byte[] waveform; public String file_name; public static DocumentAttribute TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -449,7 +452,7 @@ public class TLRPC { case 0x5910cccb: result = new TL_documentAttributeVideo(); break; - case 0xded218e0: + case 0x9852f9c6: result = new TL_documentAttributeAudio(); break; case 0x994c9882: @@ -458,6 +461,9 @@ public class TLRPC { case 0x15590068: result = new TL_documentAttributeFilename(); break; + case 0xded218e0: + result = new TL_documentAttributeAudio_layer45(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in DocumentAttribute", constructor)); @@ -526,7 +532,7 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { alt = stream.readString(exception); - stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -541,8 +547,8 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { - duration = stream.readInt32(exception); - w = stream.readInt32(exception); + duration = stream.readInt32(exception); + w = stream.readInt32(exception); h = stream.readInt32(exception); } @@ -555,20 +561,38 @@ public class TLRPC { } public static class TL_documentAttributeAudio extends DocumentAttribute { - public static int constructor = 0xded218e0; + public static int constructor = 0x9852f9c6; public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + voice = (flags & 1024) != 0; duration = stream.readInt32(exception); - title = stream.readString(exception); - performer = stream.readString(exception); + if ((flags & 1) != 0) { + title = stream.readString(exception); + } + if ((flags & 2) != 0) { + performer = stream.readString(exception); + } + if ((flags & 4) != 0) { + waveform = stream.readByteArray(exception); + } } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = voice ? (flags | 1024) : (flags &~ 1024); + stream.writeInt32(flags); stream.writeInt32(duration); - stream.writeString(title); - stream.writeString(performer); + if ((flags & 1) != 0) { + stream.writeString(title); + } + if ((flags & 2) != 0) { + stream.writeString(performer); + } + if ((flags & 4) != 0) { + stream.writeByteArray(waveform); + } } } @@ -600,6 +624,24 @@ public class TLRPC { } } + public static class TL_documentAttributeAudio_layer45 extends TL_documentAttributeAudio { + public static int constructor = 0xded218e0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + title = stream.readString(exception); + performer = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeString(title); + stream.writeString(performer); + } + } + public static class TL_contactStatus extends TLObject { public static int constructor = 0xd3680c61; @@ -1590,22 +1632,40 @@ public class TLRPC { } } - public static class TL_privacyKeyStatusTimestamp extends TLObject { + public static class PrivacyKey extends TLObject { + + public static PrivacyKey TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PrivacyKey result = null; + switch(constructor) { + case 0xbc2eab30: + result = new TL_privacyKeyStatusTimestamp(); + break; + case 0x500e6dfa: + result = new TL_privacyKeyChatInvite(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PrivacyKey", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_privacyKeyStatusTimestamp extends PrivacyKey { public static int constructor = 0xbc2eab30; - public static TL_privacyKeyStatusTimestamp TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_privacyKeyStatusTimestamp.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_privacyKeyStatusTimestamp", constructor)); - } else { - return null; - } - } - TL_privacyKeyStatusTimestamp result = new TL_privacyKeyStatusTimestamp(); - result.readParams(stream, exception); - return result; + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); } + } + + public static class TL_privacyKeyChatInvite extends PrivacyKey { + public static int constructor = 0x500e6dfa; + public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); @@ -2307,80 +2367,6 @@ public class TLRPC { } } - public static class MessageMedia extends TLObject { - public byte[] bytes; - public Video video; - public String caption; - public Photo photo; - public Audio audio; - public GeoPoint geo; - public String title; - public String address; - public String provider; - public String venue_id; - public Document document; - public String phone_number; - public String first_name; - public String last_name; - public int user_id; - public WebPage webpage; - - public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - MessageMedia result = null; - switch(constructor) { - case 0x29632a36: - result = new TL_messageMediaUnsupported_old(); - break; - case 0x5bcf1675: - result = new TL_messageMediaVideo(); - break; - case 0xc8c45a2a: - result = new TL_messageMediaPhoto_old(); - break; - case 0xc6b68300: - result = new TL_messageMediaAudio(); - break; - case 0x9f84f49e: - result = new TL_messageMediaUnsupported(); - break; - case 0x3ded6320: - result = new TL_messageMediaEmpty(); - break; - case 0x7912b71f: - result = new TL_messageMediaVenue(); - break; - case 0xa2d24290: - result = new TL_messageMediaVideo_old(); - break; - case 0x2fda2204: - result = new TL_messageMediaDocument_old(); - break; - case 0xf3e02ea8: - result = new TL_messageMediaDocument(); - break; - case 0x5e7d2f39: - result = new TL_messageMediaContact(); - break; - case 0x3d8ce53d: - result = new TL_messageMediaPhoto(); - break; - case 0xa32dd600: - result = new TL_messageMediaWebPage(); - break; - case 0x56e0d474: - result = new TL_messageMediaGeo(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in MessageMedia", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } - public static class TL_messageMediaUnsupported_old extends TL_messageMediaUnsupported { public static int constructor = 0x29632a36; @@ -2390,24 +2376,22 @@ public class TLRPC { } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); stream.writeByteArray(bytes); } } - public static class TL_messageMediaVideo extends MessageMedia { - public static int constructor = 0x5bcf1675; + public static class TL_messageMediaAudio_layer45 extends MessageMedia { + public static int constructor = 0xc6b68300; public void readParams(AbstractSerializedData stream, boolean exception) { - video = Video.TLdeserialize(stream, stream.readInt32(exception), exception); - caption = stream.readString(exception); + audio_unused = Audio.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - video.serializeToStream(stream); - stream.writeString(caption); + stream.writeInt32(constructor); + audio_unused.serializeToStream(stream); } } @@ -2415,8 +2399,8 @@ public class TLRPC { public static int constructor = 0xc8c45a2a; - public void readParams(AbstractSerializedData stream, boolean exception) { - photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + public void readParams(AbstractSerializedData stream, boolean exception) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { @@ -2425,20 +2409,6 @@ public class TLRPC { } } - public static class TL_messageMediaAudio extends MessageMedia { - public static int constructor = 0xc6b68300; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - audio = Audio.TLdeserialize(stream, stream.readInt32(exception), exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - audio.serializeToStream(stream); - } - } - public static class TL_messageMediaUnsupported extends MessageMedia { public static int constructor = 0x9f84f49e; @@ -2479,17 +2449,17 @@ public class TLRPC { } } - public static class TL_messageMediaVideo_old extends TL_messageMediaVideo { + public static class TL_messageMediaVideo_old extends TL_messageMediaVideo_layer45 { public static int constructor = 0xa2d24290; public void readParams(AbstractSerializedData stream, boolean exception) { - video = Video.TLdeserialize(stream, stream.readInt32(exception), exception); - } + video_unused = Video.TLdeserialize(stream, stream.readInt32(exception), exception); + } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - video.serializeToStream(stream); + video_unused.serializeToStream(stream); } } @@ -2497,12 +2467,12 @@ public class TLRPC { public static int constructor = 0x2fda2204; - public void readParams(AbstractSerializedData stream, boolean exception) { - document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); document.serializeToStream(stream); } } @@ -2536,7 +2506,7 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeString(phone_number); + stream.writeString(phone_number); stream.writeString(first_name); stream.writeString(last_name); stream.writeInt32(user_id); @@ -2553,23 +2523,25 @@ public class TLRPC { } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); photo.serializeToStream(stream); stream.writeString(caption); } } - public static class TL_messageMediaWebPage extends MessageMedia { - public static int constructor = 0xa32dd600; + public static class TL_messageMediaVideo_layer45 extends MessageMedia { + public static int constructor = 0x5bcf1675; public void readParams(AbstractSerializedData stream, boolean exception) { - webpage = WebPage.TLdeserialize(stream, stream.readInt32(exception), exception); + video_unused = Video.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - webpage.serializeToStream(stream); + video_unused.serializeToStream(stream); + stream.writeString(caption); } } @@ -2587,6 +2559,20 @@ public class TLRPC { } } + public static class TL_messageMediaWebPage extends MessageMedia { + public static int constructor = 0xa32dd600; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + webpage = WebPage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + webpage.serializeToStream(stream); + } + } + public static class auth_SentCode extends TLObject { public boolean phone_registered; public String phone_code_hash; @@ -2809,19 +2795,23 @@ public class TLRPC { } public static class PeerNotifySettings extends TLObject { + public int flags; + public boolean silent; public int mute_until; public String sound; - public boolean show_previews; public int events_mask; public static PeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { PeerNotifySettings result = null; switch(constructor) { - case 0x70a68512: - result = new TL_peerNotifySettingsEmpty(); + case 0x9acda4c0: + result = new TL_peerNotifySettings(); break; case 0x8d5e11ee: - result = new TL_peerNotifySettings(); + result = new TL_peerNotifySettings_layer47(); + break; + case 0x70a68512: + result = new TL_peerNotifySettingsEmpty(); break; } if (result == null && exception) { @@ -2834,18 +2824,33 @@ public class TLRPC { } } - public static class TL_peerNotifySettingsEmpty extends PeerNotifySettings { - public static int constructor = 0x70a68512; + public static class TL_peerNotifySettings extends PeerNotifySettings { + public static int constructor = 0x9acda4c0; + public boolean show_previews; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + show_previews = (flags & 1) != 0; + silent = (flags & 2) != 0; + mute_until = stream.readInt32(exception); + sound = stream.readString(exception); + } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); + flags = show_previews ? (flags | 1) : (flags &~ 1); + flags = silent ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(mute_until); + stream.writeString(sound); } } - public static class TL_peerNotifySettings extends PeerNotifySettings { + public static class TL_peerNotifySettings_layer47 extends TL_peerNotifySettings { public static int constructor = 0x8d5e11ee; + public boolean show_previews; public void readParams(AbstractSerializedData stream, boolean exception) { mute_until = stream.readInt32(exception); @@ -2863,6 +2868,15 @@ public class TLRPC { } } + public static class TL_peerNotifySettingsEmpty extends PeerNotifySettings { + public static int constructor = 0x70a68512; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class contacts_Blocked extends TLObject { public ArrayList blocked = new ArrayList<>(); public ArrayList users = new ArrayList<>(); @@ -3210,27 +3224,27 @@ public class TLRPC { public static class Audio extends TLObject { public long id; public long access_hash; - public int user_id; public int date; - public int duration; - public int size; - public int dc_id; + public int duration; public String mime_type; + public int size; + public int dc_id; + public int user_id; public byte[] key; public byte[] iv; public static Audio TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - Audio result = null; + Audio result = null; switch(constructor) { case 0x586988d8: - result = new TL_audioEmpty(); + result = new TL_audioEmpty_layer45(); break; - case 0x427425e7: + case 0xf9e35055: + result = new TL_audio_layer45(); + break; + case 0x427425e7: result = new TL_audio_old(); break; - case 0xf9e35055: - result = new TL_audio(); - break; case 0x555555F6: result = new TL_audioEncrypted(); break; @@ -3248,7 +3262,7 @@ public class TLRPC { } } - public static class TL_audioEmpty extends Audio { + public static class TL_audioEmpty_layer45 extends Audio { public static int constructor = 0x586988d8; @@ -3262,48 +3276,22 @@ public class TLRPC { } } - public static class TL_audio_old extends TL_audio { - public static int constructor = 0x427425e7; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - user_id = stream.readInt32(exception); - date = stream.readInt32(exception); - duration = stream.readInt32(exception); - size = stream.readInt32(exception); - dc_id = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - stream.writeInt32(user_id); - stream.writeInt32(date); - stream.writeInt32(duration); - stream.writeInt32(size); - stream.writeInt32(dc_id); - } - } - - public static class TL_audio extends Audio { + public static class TL_audio_layer45 extends Audio { public static int constructor = 0xf9e35055; public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); + id = stream.readInt64(exception); access_hash = stream.readInt64(exception); date = stream.readInt32(exception); - duration = stream.readInt32(exception); - mime_type = stream.readString(exception); - size = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); dc_id = stream.readInt32(exception); - } + } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); stream.writeInt64(id); stream.writeInt64(access_hash); stream.writeInt32(date); @@ -3314,19 +3302,45 @@ public class TLRPC { } } - public static class TL_audioEncrypted extends TL_audio { - public static int constructor = 0x555555F6; + public static class TL_audio_old extends TL_audio_layer45 { + public static int constructor = 0x427425e7; - public void readParams(AbstractSerializedData stream, boolean exception) { + public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt64(exception); access_hash = stream.readInt64(exception); user_id = stream.readInt32(exception); date = stream.readInt32(exception); duration = stream.readInt32(exception); - size = stream.readInt32(exception); - dc_id = stream.readInt32(exception); - key = stream.readByteArray(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeInt32(dc_id); + } + } + + public static class TL_audioEncrypted extends TL_audio_layer45 { + public static int constructor = 0x555555F6; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + key = stream.readByteArray(exception); iv = stream.readByteArray(exception); } @@ -3344,7 +3358,7 @@ public class TLRPC { } } - public static class TL_audio_old2 extends TL_audio { + public static class TL_audio_old2 extends TL_audio_layer45 { public static int constructor = 0xc7ac6496; @@ -3641,22 +3655,40 @@ public class TLRPC { } } - public static class TL_inputPrivacyKeyStatusTimestamp extends TLObject { - public static int constructor = 0x4f96cb18; + public static class InputPrivacyKey extends TLObject { - - public static TL_inputPrivacyKeyStatusTimestamp TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_inputPrivacyKeyStatusTimestamp.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_inputPrivacyKeyStatusTimestamp", constructor)); - } else { - return null; - } + public static InputPrivacyKey TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPrivacyKey result = null; + switch(constructor) { + case 0xbdfb0426: + result = new TL_inputPrivacyKeyChatInvite(); + break; + case 0x4f96cb18: + result = new TL_inputPrivacyKeyStatusTimestamp(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPrivacyKey", constructor)); + } + if (result != null) { + result.readParams(stream, exception); } - TL_inputPrivacyKeyStatusTimestamp result = new TL_inputPrivacyKeyStatusTimestamp(); - result.readParams(stream, exception); return result; } + } + + public static class TL_inputPrivacyKeyChatInvite extends InputPrivacyKey { + public static int constructor = 0xbdfb0426; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyKeyStatusTimestamp extends InputPrivacyKey { + public static int constructor = 0x4f96cb18; + public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); @@ -4017,12 +4049,13 @@ public class TLRPC { } public static class TL_inputPeerNotifySettings extends TLObject { - public static int constructor = 0x46a2ce98; + public static int constructor = 0x38935eb2; + public int flags; + public boolean show_previews; + public boolean silent; public int mute_until; public String sound; - public boolean show_previews; - public int events_mask; public static TL_inputPeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { if (TL_inputPeerNotifySettings.constructor != constructor) { @@ -4038,18 +4071,20 @@ public class TLRPC { } public void readParams(AbstractSerializedData stream, boolean exception) { - mute_until = stream.readInt32(exception); - sound = stream.readString(exception); - show_previews = stream.readBool(exception); - events_mask = stream.readInt32(exception); - } + flags = stream.readInt32(exception); + show_previews = (flags & 1) != 0; + silent = (flags & 2) != 0; + mute_until = stream.readInt32(exception); + sound = stream.readString(exception); + } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(mute_until); + stream.writeInt32(constructor); + flags = show_previews ? (flags | 1) : (flags &~ 1); + flags = silent ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(mute_until); stream.writeString(sound); - stream.writeBool(show_previews); - stream.writeInt32(events_mask); } } @@ -4391,6 +4426,9 @@ public class TLRPC { case 0xa31ea0b5: result = new TL_webPage_old(); break; + case 0xd41a5167: + result = new TL_webPageUrlPending(); + break; case 0xc586da1c: result = new TL_webPagePending(); break; @@ -4441,6 +4479,20 @@ public class TLRPC { } } + public static class TL_webPageUrlPending extends WebPage { + public static int constructor = 0xd41a5167; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + public static class TL_webPage_old extends WebPage { public static int constructor = 0xa31ea0b5; @@ -4776,15 +4828,9 @@ public class TLRPC { public static InputFileLocation TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { InputFileLocation result = null; switch(constructor) { - case 0x74dc404d: - result = new TL_inputAudioFileLocation(); - break; case 0xf5235d55: result = new TL_inputEncryptedFileLocation(); break; - case 0x3d0364ec: - result = new TL_inputVideoFileLocation(); - break; case 0x4e45abe9: result = new TL_inputDocumentFileLocation(); break; @@ -4802,22 +4848,6 @@ public class TLRPC { } } - public static class TL_inputAudioFileLocation extends InputFileLocation { - public static int constructor = 0x74dc404d; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - } - } - public static class TL_inputEncryptedFileLocation extends InputFileLocation { public static int constructor = 0xf5235d55; @@ -4834,22 +4864,6 @@ public class TLRPC { } } - public static class TL_inputVideoFileLocation extends InputFileLocation { - public static int constructor = 0x3d0364ec; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - } - } - public static class TL_inputDocumentFileLocation extends InputFileLocation { public static int constructor = 0x4e45abe9; @@ -4956,6 +4970,7 @@ public class TLRPC { public boolean explicit_content; public int bot_info_version; public boolean restricted; + public boolean min; public String restriction_reason; public String bot_inline_placeholder; @@ -5402,6 +5417,7 @@ public class TLRPC { bot_nochats = (flags & 65536) != 0; verified = (flags & 131072) != 0; restricted = (flags & 262144) != 0; + min = (flags & 1048576) != 0; id = stream.readInt32(exception); if ((flags & 1) != 0) { access_hash = stream.readInt64(exception); @@ -5446,6 +5462,7 @@ public class TLRPC { flags = bot_nochats ? (flags | 65536) : (flags &~ 65536); flags = verified ? (flags | 131072) : (flags &~ 131072); flags = restricted ? (flags | 262144) : (flags &~ 262144); + flags = min ? (flags | 1048576) : (flags &~ 1048576); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 1) != 0) { @@ -6214,26 +6231,33 @@ public class TLRPC { public static class DecryptedMessage extends TLObject { public long random_id; - public DecryptedMessageAction action; - public byte[] random_bytes; + public int ttl; public String message; public DecryptedMessageMedia media; - public int ttl; + public DecryptedMessageAction action; + public byte[] random_bytes; + public int flags; + public ArrayList entities = new ArrayList<>(); + public String via_bot_name; + public long reply_to_random_id; public static DecryptedMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { DecryptedMessage result = null; switch(constructor) { + case 0x204d3878: + result = new TL_decryptedMessage_layer17(); + break; case 0x73164160: result = new TL_decryptedMessageService(); break; - case 0x1f814f1f: - result = new TL_decryptedMessage_old(); - break; - case 0x204d3878: - result = new TL_decryptedMessage(); - break; case 0xaa48327d: - result = new TL_decryptedMessageService_old(); + result = new TL_decryptedMessageService_layer8(); + break; + case 0x1f814f1f: + result = new TL_decryptedMessage_layer8(); + break; + case 0x36b091de: + result = new TL_decryptedMessage(); break; } if (result == null && exception) { @@ -6246,6 +6270,26 @@ public class TLRPC { } } + public static class TL_decryptedMessage_layer17 extends TL_decryptedMessage { + public static int constructor = 0x204d3878; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + ttl = stream.readInt32(exception); + message = stream.readString(exception); + media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(ttl); + stream.writeString(message); + media.serializeToStream(stream); + } + } + public static class TL_decryptedMessageService extends DecryptedMessage { public static int constructor = 0x73164160; @@ -6262,20 +6306,38 @@ public class TLRPC { } } - public static class TL_decryptedMessage_old extends TL_decryptedMessage { + public static class TL_decryptedMessageService_layer8 extends TL_decryptedMessageService { + public static int constructor = 0xaa48327d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + random_bytes = stream.readByteArray(exception); + action = DecryptedMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeByteArray(random_bytes); + action.serializeToStream(stream); + } + } + + public static class TL_decryptedMessage_layer8 extends TL_decryptedMessage { public static int constructor = 0x1f814f1f; public void readParams(AbstractSerializedData stream, boolean exception) { random_id = stream.readInt64(exception); - random_bytes = stream.readByteArray(exception); + random_bytes = stream.readByteArray(exception); message = stream.readString(exception); media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(random_id); + stream.writeInt64(random_id); stream.writeByteArray(random_bytes); stream.writeString(message); media.serializeToStream(stream); @@ -6283,40 +6345,65 @@ public class TLRPC { } public static class TL_decryptedMessage extends DecryptedMessage { - public static int constructor = 0x204d3878; + public static int constructor = 0x36b091de; public void readParams(AbstractSerializedData stream, boolean exception) { - random_id = stream.readInt64(exception); - ttl = stream.readInt32(exception); + flags = stream.readInt32(exception); + random_id = stream.readInt64(exception); + ttl = stream.readInt32(exception); message = stream.readString(exception); - media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 512) != 0) { + media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + 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++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 2048) != 0) { + via_bot_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + reply_to_random_id = stream.readInt64(exception); + } } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); + stream.writeInt32(flags); stream.writeInt64(random_id); stream.writeInt32(ttl); stream.writeString(message); - media.serializeToStream(stream); - } - } - - public static class TL_decryptedMessageService_old extends TL_decryptedMessageService { - public static int constructor = 0xaa48327d; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - random_id = stream.readInt64(exception); - random_bytes = stream.readByteArray(exception); - action = DecryptedMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(random_id); - stream.writeByteArray(random_bytes); - action.serializeToStream(stream); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 2048) != 0) { + stream.writeString(via_bot_name); + } + if ((flags & 8) != 0) { + stream.writeInt64(reply_to_random_id); + } } } @@ -6330,15 +6417,15 @@ public class TLRPC { break; case 0xf03064d8: result = new TL_inputPeerNotifyEventsEmpty(); - break; - } + break; + } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in InputPeerNotifyEvents", constructor)); } if (result != null) { result.readParams(stream, exception); - } - return result; + } + return result; } } @@ -6363,52 +6450,84 @@ public class TLRPC { public static class Video extends TLObject { public long id; public long access_hash; + public int user_id; public int date; public int duration; - public String mime_type; public int size; public PhotoSize thumb; public int dc_id; public int w; public int h; - public int user_id; + public String mime_type; public String caption; public byte[] key; public byte[] iv; public static Video TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - Video result = null; + Video result = null; switch(constructor) { - case 0xf72887d3: - result = new TL_video(); - break; case 0xee9f4a4d: result = new TL_video_old3(); - break; + break; + case 0xf72887d3: + result = new TL_video_layer45(); + break; case 0x55555553: - result = new TL_videoEncrypted(); + result = new TL_videoEncrypted(); break; case 0x5a04a49f: result = new TL_video_old(); break; case 0x388fa391: result = new TL_video_old2(); - break; + break; case 0xc10658a8: - result = new TL_videoEmpty(); + result = new TL_videoEmpty_layer45(); break; } - if (result == null && exception) { + if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in Video", constructor)); } if (result != null) { result.readParams(stream, exception); } - return result; + return result; } } - public static class TL_video extends Video { + public static class TL_video_old3 extends TL_video_layer45 { + public static int constructor = 0xee9f4a4d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_video_layer45 extends Video { public static int constructor = 0xf72887d3; @@ -6429,41 +6548,9 @@ public class TLRPC { stream.writeInt32(constructor); stream.writeInt64(id); stream.writeInt64(access_hash); - stream.writeInt32(date); - stream.writeInt32(duration); - stream.writeString(mime_type); - stream.writeInt32(size); - thumb.serializeToStream(stream); - stream.writeInt32(dc_id); - stream.writeInt32(w); - stream.writeInt32(h); - } - } - - public static class TL_video_old3 extends TL_video { - public static int constructor = 0xee9f4a4d; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - user_id = stream.readInt32(exception); - date = stream.readInt32(exception); - duration = stream.readInt32(exception); - size = stream.readInt32(exception); - thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); - dc_id = stream.readInt32(exception); - w = stream.readInt32(exception); - h = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - stream.writeInt32(user_id); stream.writeInt32(date); stream.writeInt32(duration); + stream.writeString(mime_type); stream.writeInt32(size); thumb.serializeToStream(stream); stream.writeInt32(dc_id); @@ -6472,14 +6559,14 @@ public class TLRPC { } } - public static class TL_videoEncrypted extends TL_video { + public static class TL_videoEncrypted extends TL_video_layer45 { public static int constructor = 0x55555553; public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - user_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); date = stream.readInt32(exception); caption = stream.readString(exception); duration = stream.readInt32(exception); @@ -6488,14 +6575,14 @@ public class TLRPC { dc_id = stream.readInt32(exception); w = stream.readInt32(exception); h = stream.readInt32(exception); - key = stream.readByteArray(exception); + key = stream.readByteArray(exception); iv = stream.readByteArray(exception); } public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt64(id); - stream.writeInt64(access_hash); + stream.writeInt64(access_hash); stream.writeInt32(user_id); stream.writeInt32(date); stream.writeString(caption); @@ -6510,7 +6597,7 @@ public class TLRPC { } } - public static class TL_video_old extends TL_video { + public static class TL_video_old extends TL_video_layer45 { public static int constructor = 0x5a04a49f; @@ -6518,7 +6605,7 @@ public class TLRPC { id = stream.readInt64(exception); access_hash = stream.readInt64(exception); user_id = stream.readInt32(exception); - date = stream.readInt32(exception); + date = stream.readInt32(exception); caption = stream.readString(exception); duration = stream.readInt32(exception); size = stream.readInt32(exception); @@ -6533,29 +6620,29 @@ public class TLRPC { stream.writeInt64(id); stream.writeInt64(access_hash); stream.writeInt32(user_id); - stream.writeInt32(date); + stream.writeInt32(date); stream.writeString(caption); stream.writeInt32(duration); stream.writeInt32(size); - thumb.serializeToStream(stream); + thumb.serializeToStream(stream); stream.writeInt32(dc_id); stream.writeInt32(w); stream.writeInt32(h); } } - public static class TL_video_old2 extends TL_video { + public static class TL_video_old2 extends TL_video_layer45 { public static int constructor = 0x388fa391; public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt64(exception); access_hash = stream.readInt64(exception); - user_id = stream.readInt32(exception); - date = stream.readInt32(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); caption = stream.readString(exception); duration = stream.readInt32(exception); - mime_type = stream.readString(exception); + mime_type = stream.readString(exception); size = stream.readInt32(exception); thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); dc_id = stream.readInt32(exception); @@ -6565,10 +6652,10 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - stream.writeInt64(id); + stream.writeInt64(id); stream.writeInt64(access_hash); - stream.writeInt32(user_id); - stream.writeInt32(date); + stream.writeInt32(user_id); + stream.writeInt32(date); stream.writeString(caption); stream.writeInt32(duration); stream.writeString(mime_type); @@ -6580,7 +6667,7 @@ public class TLRPC { } } - public static class TL_videoEmpty extends Video { + public static class TL_videoEmpty_layer45 extends Video { public static int constructor = 0xc10658a8; @@ -6591,7 +6678,35 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt64(id); - } + } + } + + public static class TL_exportedMessageLink extends TLObject { + public static int constructor = 0x1f486803; + + public String link; + + public static TL_exportedMessageLink TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_exportedMessageLink.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_exportedMessageLink", constructor)); + } else { + return null; + } + } + TL_exportedMessageLink result = new TL_exportedMessageLink(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + link = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(link); + } } public static class TL_contactBlocked extends TLObject { @@ -6875,7 +6990,15 @@ public class TLRPC { id = stream.readInt64(exception); access_hash = stream.readInt64(exception); date = stream.readInt32(exception); - mime_type = stream.readString(exception); + int startReadPosiition = stream.getPosition(); //TODO remove this hack after some time + try { + mime_type = stream.readString(true); + } catch (Exception e) { + mime_type = "audio/ogg"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } size = stream.readInt32(exception); thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); dc_id = stream.readInt32(exception); @@ -7167,67 +7290,45 @@ public class TLRPC { } public static class InputMedia extends TLObject { - public String phone_number; - public String first_name; - public String last_name; public InputFile file; public InputFile thumb; public String mime_type; public ArrayList attributes = new ArrayList<>(); public String caption; - public String url; - public String q; - public int flags; public InputGeoPoint geo_point; - public int duration; - public int w; - public int h; public String title; public String address; public String provider; public String venue_id; + public String phone_number; + public String first_name; + public String last_name; + public String url; + public String q; public static InputMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { InputMedia result = null; switch(constructor) { - case 0xa6e45987: - result = new TL_inputMediaContact(); - break; case 0xad613491: result = new TL_inputMediaUploadedThumbDocument(); break; - case 0x89938781: - result = new TL_inputMediaAudio(); - break; - case 0x1a77f29c: - result = new TL_inputMediaDocument(); - break; - case 0x936a4ebd: - result = new TL_inputMediaVideo(); - break; - case 0x4843b0fd: - result = new TL_inputMediaGifExternal(); - break; - case 0xf9c44144: - result = new TL_inputMediaGeoPoint(); - break; - case 0x9664f57f: - result = new TL_inputMediaEmpty(); - break; - case 0x7780ddf9: - result = new TL_inputMediaUploadedThumbVideo(); - break; case 0xf7aff1c0: result = new TL_inputMediaUploadedPhoto(); break; + case 0xf9c44144: + result = new TL_inputMediaGeoPoint(); + break; case 0x2827a81a: result = new TL_inputMediaVenue(); break; - case 0x4e498cab: - result = new TL_inputMediaUploadedAudio(); + case 0xa6e45987: + result = new TL_inputMediaContact(); break; - case 0x82713fdf: - result = new TL_inputMediaUploadedVideo(); + case 0x1a77f29c: + result = new TL_inputMediaDocument(); + break; + case 0x4843b0fd: + result = new TL_inputMediaGifExternal(); break; case 0x1d89306d: result = new TL_inputMediaUploadedDocument(); @@ -7235,6 +7336,9 @@ public class TLRPC { case 0xe9bfb4f3: result = new TL_inputMediaPhoto(); break; + case 0x9664f57f: + result = new TL_inputMediaEmpty(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in InputMedia", constructor)); @@ -7305,21 +7409,6 @@ public class TLRPC { } } - public static class TL_inputMediaAudio extends InputMedia { - public static int constructor = 0x89938781; - - public InputAudio id; - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = InputAudio.TLdeserialize(stream, stream.readInt32(exception), exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - id.serializeToStream(stream); - } - } - public static class TL_inputMediaDocument extends InputMedia { public static int constructor = 0x1a77f29c; @@ -7337,23 +7426,6 @@ public class TLRPC { } } - public static class TL_inputMediaVideo extends InputMedia { - public static int constructor = 0x936a4ebd; - - public InputVideo id; - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = InputVideo.TLdeserialize(stream, stream.readInt32(exception), exception); - caption = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - id.serializeToStream(stream); - stream.writeString(caption); - } - } - public static class TL_inputMediaGifExternal extends InputMedia { public static int constructor = 0x4843b0fd; @@ -7393,32 +7465,6 @@ public class TLRPC { } } - public static class TL_inputMediaUploadedThumbVideo extends InputMedia { - public static int constructor = 0x7780ddf9; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); - thumb = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); - duration = stream.readInt32(exception); - w = stream.readInt32(exception); - h = stream.readInt32(exception); - mime_type = stream.readString(exception); - caption = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - file.serializeToStream(stream); - thumb.serializeToStream(stream); - stream.writeInt32(duration); - stream.writeInt32(w); - stream.writeInt32(h); - stream.writeString(mime_type); - stream.writeString(caption); - } - } - public static class TL_inputMediaUploadedPhoto extends InputMedia { public static int constructor = 0xf7aff1c0; @@ -7457,48 +7503,6 @@ public class TLRPC { } } - public static class TL_inputMediaUploadedAudio extends InputMedia { - public static int constructor = 0x4e498cab; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); - duration = stream.readInt32(exception); - mime_type = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - file.serializeToStream(stream); - stream.writeInt32(duration); - stream.writeString(mime_type); - } - } - - public static class TL_inputMediaUploadedVideo extends InputMedia { - public static int constructor = 0x82713fdf; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); - duration = stream.readInt32(exception); - w = stream.readInt32(exception); - h = stream.readInt32(exception); - mime_type = stream.readString(exception); - caption = stream.readString(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - file.serializeToStream(stream); - stream.writeInt32(duration); - stream.writeInt32(w); - stream.writeInt32(h); - stream.writeString(mime_type); - stream.writeString(caption); - } - } - public static class TL_inputMediaUploadedDocument extends InputMedia { public static int constructor = 0x1d89306d; @@ -7844,12 +7848,12 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); + id = stream.readInt64(exception); access_hash = stream.readInt64(exception); } public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); + stream.writeInt32(constructor); stream.writeInt64(id); stream.writeInt64(access_hash); } @@ -7859,7 +7863,7 @@ public class TLRPC { public static int constructor = 0x861cc8a0; - public void readParams(AbstractSerializedData stream, boolean exception) { + public void readParams(AbstractSerializedData stream, boolean exception) { short_name = stream.readString(exception); } @@ -7869,37 +7873,6 @@ public class TLRPC { } } - public static class TL_contactSuggested extends TLObject { - public static int constructor = 0x3de191a1; - - public int user_id; - public int mutual_contacts; - - public static TL_contactSuggested TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_contactSuggested.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_contactSuggested", constructor)); - } else { - return null; - } - } - TL_contactSuggested result = new TL_contactSuggested(); - result.readParams(stream, exception); - return result; - } - - public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt32(exception); - mutual_contacts = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(user_id); - stream.writeInt32(mutual_contacts); - } - } - public static class UserStatus extends TLObject { public int expires; @@ -8139,7 +8112,7 @@ public class TLRPC { public long random_id; public ArrayList dc_options = new ArrayList<>(); public ChatParticipants participants; - public TL_privacyKeyStatusTimestamp key; + public PrivacyKey key; public ArrayList rules = new ArrayList<>(); public UserStatus status; public int views; @@ -8172,6 +8145,9 @@ public class TLRPC { case 0x43ae3dec: result = new TL_updateStickerSets(); break; + case 0x1b3f4df7: + result = new TL_updateEditChannelMessage(); + break; case 0xbec268ef: result = new TL_updateNotifySettings(); break; @@ -8334,6 +8310,25 @@ public class TLRPC { } } + public static class TL_updateEditChannelMessage extends Update { + public static int constructor = 0x1b3f4df7; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + public static class TL_updateNotifySettings extends Update { public static int constructor = 0xbec268ef; @@ -8598,7 +8593,7 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { - key = TL_privacyKeyStatusTimestamp.TLdeserialize(stream, stream.readInt32(exception), exception); + key = PrivacyKey.TLdeserialize(stream, stream.readInt32(exception), exception); int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -9111,75 +9106,6 @@ public class TLRPC { } } - public static class TL_contacts_suggested extends TLObject { - public static int constructor = 0x5649dcc5; - - public ArrayList results = new ArrayList<>(); - public ArrayList users = new ArrayList<>(); - - public static TL_contacts_suggested TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - if (TL_contacts_suggested.constructor != constructor) { - if (exception) { - throw new RuntimeException(String.format("can't parse magic %x in TL_contacts_suggested", constructor)); - } else { - return null; - } - } - TL_contacts_suggested result = new TL_contacts_suggested(); - result.readParams(stream, exception); - return result; - } - - public void readParams(AbstractSerializedData stream, boolean 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++) { - TL_contactSuggested object = TL_contactSuggested.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - results.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++) { - User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - users.add(object); - } - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(0x1cb5c415); - int count = results.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - results.get(a).serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - } - } - public static class TL_receivedNotifyMessage extends TLObject { public static int constructor = 0xa384b779; @@ -10476,7 +10402,7 @@ public class TLRPC { } public static class TL_config extends TLObject { - public static int constructor = 0x6bbc5f8; + public static int constructor = 0x317ceef4; public int date; public int expires; @@ -10496,6 +10422,7 @@ public class TLRPC { public int push_chat_period_ms; public int push_chat_limit; public int saved_gifs_limit; + public int edit_time_limit; public ArrayList disabled_features = new ArrayList<>(); public static TL_config TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { @@ -10544,6 +10471,7 @@ public class TLRPC { push_chat_period_ms = stream.readInt32(exception); push_chat_limit = stream.readInt32(exception); saved_gifs_limit = stream.readInt32(exception); + edit_time_limit = stream.readInt32(exception); magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -10586,6 +10514,7 @@ public class TLRPC { stream.writeInt32(push_chat_period_ms); stream.writeInt32(push_chat_limit); stream.writeInt32(saved_gifs_limit); + stream.writeInt32(edit_time_limit); stream.writeInt32(0x1cb5c415); count = disabled_features.size(); stream.writeInt32(count); @@ -10595,55 +10524,6 @@ public class TLRPC { } } - public static class InputAudio extends TLObject { - public long id; - public long access_hash; - - public static InputAudio TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - InputAudio result = null; - switch(constructor) { - case 0x77d440ff: - result = new TL_inputAudio(); - break; - case 0xd95adc84: - result = new TL_inputAudioEmpty(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in InputAudio", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } - - public static class TL_inputAudio extends InputAudio { - public static int constructor = 0x77d440ff; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - } - } - - public static class TL_inputAudioEmpty extends InputAudio { - public static int constructor = 0xd95adc84; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } - public static class TL_help_support extends TLObject { public static int constructor = 0x17c6b5f6; @@ -11828,64 +11708,85 @@ public class TLRPC { } public static class DecryptedMessageMedia extends TLObject { - public int thumb_w; - public int thumb_h; - public String file_name; - public String mime_type; - public int size; - public byte[] key; - public byte[] iv; - public long id; - public long access_hash; - public int date; - public int dc_id; - public ArrayList attributes = new ArrayList<>(); public int duration; + public String mime_type; + public int size; + public byte[] key; + public byte[] iv; public double lat; public double _long; - public int w; - public int h; public String phone_number; public String first_name; public String last_name; public int user_id; + public int thumb_w; + public int thumb_h; + public ArrayList attributes = new ArrayList<>(); + public String caption; + public String url; + public int w; + public int h; + public String file_name; + public String title; + public String address; + public String provider; + public String venue_id; + public long id; + public long access_hash; + public int date; + public int dc_id; public static DecryptedMessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { DecryptedMessageMedia result = null; switch(constructor) { - case 0x89f5c4a: - result = new TL_decryptedMessageMediaEmpty(); - break; - case 0xb095434b: - result = new TL_decryptedMessageMediaDocument(); - break; - case 0xfa95b0dd: - result = new TL_decryptedMessageMediaExternalDocument(); - break; - case 0x6080758f: - result = new TL_decryptedMessageMediaAudio_old(); - break; - case 0x35480a59: - result = new TL_decryptedMessageMediaGeoPoint(); - break; case 0x57e0a9cb: result = new TL_decryptedMessageMediaAudio(); break; - case 0x524a415d: - result = new TL_decryptedMessageMediaVideo(); + case 0x35480a59: + result = new TL_decryptedMessageMediaGeoPoint(); break; case 0x588a0a97: result = new TL_decryptedMessageMediaContact(); break; - case 0x32798a8c: + case 0x89f5c4a: + result = new TL_decryptedMessageMediaEmpty(); + break; + case 0x7afe8ae2: + result = new TL_decryptedMessageMediaDocument(); + break; + case 0xe50511d8: + result = new TL_decryptedMessageMediaWebPage(); + break; + case 0xf1fa8d78: result = new TL_decryptedMessageMediaPhoto(); break; + case 0x970c8c0e: + result = new TL_decryptedMessageMediaVideo(); + break; + case 0xb095434b: + result = new TL_decryptedMessageMediaDocument_layer8(); + break; case 0x4cee6ef3: - result = new TL_decryptedMessageMediaVideo_old(); + result = new TL_decryptedMessageMediaVideo_layer8(); + break; + case 0x8a0df56f: + result = new TL_decryptedMessageMediaVenue(); + break; + case 0xfa95b0dd: + result = new TL_decryptedMessageMediaExternalDocument(); + break; + case 0x524a415d: + result = new TL_decryptedMessageMediaVideo_layer17(); + break; + case 0x6080758f: + result = new TL_decryptedMessageMediaAudio_layer8(); + break; + case 0x32798a8c: + result = new TL_decryptedMessageMediaPhoto_layer8(); break; } if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in DecryptedMessageMedia", constructor)); + throw new RuntimeException(String.format("can't parse magic %x in DecryptedMessageMedia", constructor)); } if (result != null) { result.readParams(stream, exception); @@ -11894,6 +11795,64 @@ public class TLRPC { } } + public static class TL_decryptedMessageMediaAudio extends DecryptedMessageMedia { + public static int constructor = 0x57e0a9cb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaGeoPoint extends DecryptedMessageMedia { + public static int constructor = 0x35480a59; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(lat); + stream.writeDouble(_long); + } + } + + public static class TL_decryptedMessageMediaContact extends DecryptedMessageMedia { + public static int constructor = 0x588a0a97; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt32(user_id); + } + } + public static class TL_decryptedMessageMediaEmpty extends DecryptedMessageMedia { public static int constructor = 0x89f5c4a; @@ -11904,6 +11863,136 @@ public class TLRPC { } public static class TL_decryptedMessageMediaDocument extends DecryptedMessageMedia { + public static int constructor = 0x7afe8ae2; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(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++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaWebPage extends DecryptedMessageMedia { + public static int constructor = 0xe50511d8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + + public static class TL_decryptedMessageMediaPhoto extends DecryptedMessageMedia { + public static int constructor = 0xf1fa8d78; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaVideo extends DecryptedMessageMedia { + public static int constructor = 0x970c8c0e; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaDocument_layer8 extends TL_decryptedMessageMediaDocument { public static int constructor = 0xb095434b; public byte[] thumb; @@ -11932,195 +12021,7 @@ public class TLRPC { } } - public static class TL_decryptedMessageMediaExternalDocument extends DecryptedMessageMedia { - public static int constructor = 0xfa95b0dd; - - public PhotoSize thumb; - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - date = stream.readInt32(exception); - mime_type = stream.readString(exception); - size = stream.readInt32(exception); - thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); - dc_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++) { - DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - attributes.add(object); - } - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - stream.writeInt32(date); - stream.writeString(mime_type); - stream.writeInt32(size); - thumb.serializeToStream(stream); - stream.writeInt32(dc_id); - stream.writeInt32(0x1cb5c415); - int count = attributes.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - attributes.get(a).serializeToStream(stream); - } - } - } - - public static class TL_decryptedMessageMediaAudio_old extends TL_decryptedMessageMediaAudio { - public static int constructor = 0x6080758f; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - duration = stream.readInt32(exception); - size = stream.readInt32(exception); - key = stream.readByteArray(exception); - iv = stream.readByteArray(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(duration); - stream.writeInt32(size); - stream.writeByteArray(key); - stream.writeByteArray(iv); - } - } - - public static class TL_decryptedMessageMediaGeoPoint extends DecryptedMessageMedia { - public static int constructor = 0x35480a59; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - lat = stream.readDouble(exception); - _long = stream.readDouble(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeDouble(lat); - stream.writeDouble(_long); - } - } - - public static class TL_decryptedMessageMediaAudio extends DecryptedMessageMedia { - public static int constructor = 0x57e0a9cb; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - duration = stream.readInt32(exception); - mime_type = stream.readString(exception); - size = stream.readInt32(exception); - key = stream.readByteArray(exception); - iv = stream.readByteArray(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(duration); - stream.writeString(mime_type); - stream.writeInt32(size); - stream.writeByteArray(key); - stream.writeByteArray(iv); - } - } - - public static class TL_decryptedMessageMediaVideo extends DecryptedMessageMedia { - public static int constructor = 0x524a415d; - - public byte[] thumb; - - public void readParams(AbstractSerializedData stream, boolean exception) { - thumb = stream.readByteArray(exception); - thumb_w = stream.readInt32(exception); - thumb_h = stream.readInt32(exception); - duration = stream.readInt32(exception); - mime_type = stream.readString(exception); - w = stream.readInt32(exception); - h = stream.readInt32(exception); - size = stream.readInt32(exception); - key = stream.readByteArray(exception); - iv = stream.readByteArray(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(thumb); - stream.writeInt32(thumb_w); - stream.writeInt32(thumb_h); - stream.writeInt32(duration); - stream.writeString(mime_type); - stream.writeInt32(w); - stream.writeInt32(h); - stream.writeInt32(size); - stream.writeByteArray(key); - stream.writeByteArray(iv); - } - } - - public static class TL_decryptedMessageMediaContact extends DecryptedMessageMedia { - public static int constructor = 0x588a0a97; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - phone_number = stream.readString(exception); - first_name = stream.readString(exception); - last_name = stream.readString(exception); - user_id = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeString(phone_number); - stream.writeString(first_name); - stream.writeString(last_name); - stream.writeInt32(user_id); - } - } - - public static class TL_decryptedMessageMediaPhoto extends DecryptedMessageMedia { - public static int constructor = 0x32798a8c; - - public byte[] thumb; - - public void readParams(AbstractSerializedData stream, boolean exception) { - thumb = stream.readByteArray(exception); - thumb_w = stream.readInt32(exception); - thumb_h = stream.readInt32(exception); - w = stream.readInt32(exception); - h = stream.readInt32(exception); - size = stream.readInt32(exception); - key = stream.readByteArray(exception); - iv = stream.readByteArray(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeByteArray(thumb); - stream.writeInt32(thumb_w); - stream.writeInt32(thumb_h); - stream.writeInt32(w); - stream.writeInt32(h); - stream.writeInt32(size); - stream.writeByteArray(key); - stream.writeByteArray(iv); - } - } - - public static class TL_decryptedMessageMediaVideo_old extends TL_decryptedMessageMediaVideo { + public static class TL_decryptedMessageMediaVideo_layer8 extends TL_decryptedMessageMediaVideo { public static int constructor = 0x4cee6ef3; public byte[] thumb; @@ -12145,7 +12046,161 @@ public class TLRPC { stream.writeInt32(duration); stream.writeInt32(w); stream.writeInt32(h); - stream.writeInt32(size); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaVenue extends DecryptedMessageMedia { + public static int constructor = 0x8a0df56f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(lat); + stream.writeDouble(_long); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + } + } + + public static class TL_decryptedMessageMediaExternalDocument extends DecryptedMessageMedia { + public static int constructor = 0xfa95b0dd; + + public PhotoSize thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_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++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + } + } + + public static class TL_decryptedMessageMediaVideo_layer17 extends TL_decryptedMessageMediaVideo { + public static int constructor = 0x524a415d; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaAudio_layer8 extends TL_decryptedMessageMediaAudio { + public static int constructor = 0x6080758f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaPhoto_layer8 extends TL_decryptedMessageMediaPhoto { + public static int constructor = 0x32798a8c; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); stream.writeByteArray(key); stream.writeByteArray(iv); } @@ -12252,6 +12307,8 @@ public class TLRPC { public long access_hash; public String username; public boolean restricted; + public boolean democracy; + public boolean signatures; public String restriction_reason; public InputChannel migrated_to; public String address; @@ -12557,6 +12614,8 @@ public class TLRPC { verified = (flags & 128) != 0; megagroup = (flags & 256) != 0; restricted = (flags & 512) != 0; + democracy = (flags & 1024) != 0; + signatures = (flags & 2048) != 0; id = stream.readInt32(exception); access_hash = stream.readInt64(exception); title = stream.readString(exception); @@ -12582,6 +12641,8 @@ public class TLRPC { flags = verified ? (flags | 128) : (flags &~ 128); flags = megagroup ? (flags | 256) : (flags &~ 256); flags = restricted ? (flags | 512) : (flags &~ 512); + flags = democracy ? (flags | 1024) : (flags &~ 1024); + flags = signatures ? (flags | 2048) : (flags &~ 2048); stream.writeInt32(flags); stream.writeInt32(id); stream.writeInt64(access_hash); @@ -12826,8 +12887,8 @@ public class TLRPC { case 0x9eddf188: result = new TL_inputMessagesFilterDocument(); break; - case 0x5afbf764: - result = new TL_inputMessagesFilterAudioDocuments(); + case 0x3751b49e: + result = new TL_inputMessagesFilterMusic(); break; case 0x9fc00e65: result = new TL_inputMessagesFilterVideo(); @@ -12838,15 +12899,15 @@ public class TLRPC { case 0xd95e73bb: result = new TL_inputMessagesFilterPhotoVideoDocuments(); break; - case 0xcfc87522: - result = new TL_inputMessagesFilterAudio(); - break; case 0x7ef0dd87: result = new TL_inputMessagesFilterUrl(); break; case 0xffc86587: result = new TL_inputMessagesFilterGif(); break; + case 0x50f5c392: + result = new TL_inputMessagesFilterVoice(); + break; case 0x57e2f66c: result = new TL_inputMessagesFilterEmpty(); break; @@ -12873,8 +12934,8 @@ public class TLRPC { } } - public static class TL_inputMessagesFilterAudioDocuments extends MessagesFilter { - public static int constructor = 0x5afbf764; + public static class TL_inputMessagesFilterMusic extends MessagesFilter { + public static int constructor = 0x3751b49e; public void serializeToStream(AbstractSerializedData stream) { @@ -12909,15 +12970,6 @@ public class TLRPC { } } - public static class TL_inputMessagesFilterAudio extends MessagesFilter { - public static int constructor = 0xcfc87522; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } - public static class TL_inputMessagesFilterUrl extends MessagesFilter { public static int constructor = 0x7ef0dd87; @@ -12936,6 +12988,15 @@ public class TLRPC { } } + public static class TL_inputMessagesFilterVoice extends MessagesFilter { + public static int constructor = 0x50f5c392; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_inputMessagesFilterEmpty extends MessagesFilter { public static int constructor = 0x57e2f66c; @@ -13089,6 +13150,58 @@ public class TLRPC { } } + public static class TL_messageFwdHeader extends TLObject { + public static int constructor = 0xc786ddcb; + + public int flags; + public int from_id; + public int date; + public int channel_id; + public int channel_post; + + public static TL_messageFwdHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messageFwdHeader.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messageFwdHeader", constructor)); + } else { + return null; + } + } + TL_messageFwdHeader result = new TL_messageFwdHeader(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + from_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + if ((flags & 2) != 0) { + channel_id = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + channel_post = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(from_id); + } + stream.writeInt32(date); + if ((flags & 2) != 0) { + stream.writeInt32(channel_id); + } + if ((flags & 4) != 0) { + stream.writeInt32(channel_post); + } + } + } + public static class FileLocation extends TLObject { public int dc_id; public long volume_id; @@ -13370,7 +13483,21 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { - type = stream.readString(exception); + int startReadPosiition = stream.getPosition(); //TODO remove this hack after some time + try { + type = stream.readString(true); + if (type.length() > 1 || !type.equals("") && !type.equals("s") && !type.equals("x") && !type.equals("m") && !type.equals("y") && !type.equals("w")) { + type = "s"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } + } catch (Exception e) { + type = "s"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } } public void serializeToStream(AbstractSerializedData stream) { @@ -13633,13 +13760,13 @@ public class TLRPC { public boolean out; public boolean mentioned; public boolean media_unread; + public boolean silent; public int id; public int user_id; public String message; public int pts; public int pts_count; - public Peer fwd_from_id; - public int fwd_date; + public TL_messageFwdHeader fwd_from; public int via_bot_id; public int reply_to_msg_id; public ArrayList entities = new ArrayList<>(); @@ -13655,7 +13782,7 @@ public class TLRPC { case 0x74ae4240: result = new TL_updates(); break; - case 0x13e4deaa: + case 0x914fbf11: result = new TL_updateShortMessage(); break; case 0x11f1331c: @@ -13664,7 +13791,7 @@ public class TLRPC { case 0x78d4dec1: result = new TL_updateShort(); break; - case 0x248afa62: + case 0x16812688: result = new TL_updateShortChatMessage(); break; case 0x725b04c3: @@ -13737,34 +13864,10 @@ public class TLRPC { date = stream.readInt32(exception); seq = stream.readInt32(exception); } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(0x1cb5c415); - int count = updates.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - updates.get(a).serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - count = chats.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - chats.get(a).serializeToStream(stream); - } - stream.writeInt32(date); - stream.writeInt32(seq); - } } public static class TL_updateShortMessage extends Updates { - public static int constructor = 0x13e4deaa; + public static int constructor = 0x914fbf11; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -13773,6 +13876,7 @@ public class TLRPC { out = (flags & 2) != 0; mentioned = (flags & 16) != 0; media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; id = stream.readInt32(exception); user_id = stream.readInt32(exception); message = stream.readString(exception); @@ -13780,10 +13884,7 @@ public class TLRPC { pts_count = stream.readInt32(exception); date = stream.readInt32(exception); if ((flags & 4) != 0) { - fwd_from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 2048) != 0) { via_bot_id = stream.readInt32(exception); @@ -13809,41 +13910,6 @@ public class TLRPC { } } } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = unread ? (flags | 1) : (flags &~ 1); - flags = out ? (flags | 2) : (flags &~ 2); - flags = mentioned ? (flags | 16) : (flags &~ 16); - flags = media_unread ? (flags | 32) : (flags &~ 32); - stream.writeInt32(flags); - stream.writeInt32(id); - stream.writeInt32(user_id); - stream.writeString(message); - stream.writeInt32(pts); - stream.writeInt32(pts_count); - stream.writeInt32(date); - if ((flags & 4) != 0) { - fwd_from_id.serializeToStream(stream); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); - } - if ((flags & 2048) != 0) { - stream.writeInt32(via_bot_id); - } - if ((flags & 8) != 0) { - stream.writeInt32(reply_to_msg_id); - } - if ((flags & 128) != 0) { - stream.writeInt32(0x1cb5c415); - int count = entities.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - entities.get(a).serializeToStream(stream); - } - } - } } public static class TL_updateShortSentMessage extends Updates { @@ -13879,28 +13945,6 @@ public class TLRPC { } } } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = unread ? (flags | 1) : (flags &~ 1); - flags = out ? (flags | 2) : (flags &~ 2); - stream.writeInt32(flags); - stream.writeInt32(id); - stream.writeInt32(pts); - stream.writeInt32(pts_count); - stream.writeInt32(date); - if ((flags & 512) != 0) { - media.serializeToStream(stream); - } - if ((flags & 128) != 0) { - stream.writeInt32(0x1cb5c415); - int count = entities.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - entities.get(a).serializeToStream(stream); - } - } - } } public static class TL_updateShort extends Updates { @@ -13911,16 +13955,10 @@ public class TLRPC { update = Update.TLdeserialize(stream, stream.readInt32(exception), exception); date = stream.readInt32(exception); } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - update.serializeToStream(stream); - stream.writeInt32(date); - } } public static class TL_updateShortChatMessage extends Updates { - public static int constructor = 0x248afa62; + public static int constructor = 0x16812688; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -13929,6 +13967,7 @@ public class TLRPC { out = (flags & 2) != 0; mentioned = (flags & 16) != 0; media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; id = stream.readInt32(exception); from_id = stream.readInt32(exception); chat_id = stream.readInt32(exception); @@ -13937,10 +13976,7 @@ public class TLRPC { pts_count = stream.readInt32(exception); date = stream.readInt32(exception); if ((flags & 4) != 0) { - fwd_from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); } if ((flags & 2048) != 0) { via_bot_id = stream.readInt32(exception); @@ -13966,42 +14002,6 @@ public class TLRPC { } } } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - flags = unread ? (flags | 1) : (flags &~ 1); - flags = out ? (flags | 2) : (flags &~ 2); - flags = mentioned ? (flags | 16) : (flags &~ 16); - flags = media_unread ? (flags | 32) : (flags &~ 32); - stream.writeInt32(flags); - stream.writeInt32(id); - stream.writeInt32(from_id); - stream.writeInt32(chat_id); - stream.writeString(message); - stream.writeInt32(pts); - stream.writeInt32(pts_count); - stream.writeInt32(date); - if ((flags & 4) != 0) { - fwd_from_id.serializeToStream(stream); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); - } - if ((flags & 2048) != 0) { - stream.writeInt32(via_bot_id); - } - if ((flags & 8) != 0) { - stream.writeInt32(reply_to_msg_id); - } - if ((flags & 128) != 0) { - stream.writeInt32(0x1cb5c415); - int count = entities.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - entities.get(a).serializeToStream(stream); - } - } - } } public static class TL_updatesCombined extends Updates { @@ -14058,40 +14058,10 @@ public class TLRPC { seq_start = stream.readInt32(exception); seq = stream.readInt32(exception); } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(0x1cb5c415); - int count = updates.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - updates.get(a).serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - stream.writeInt32(0x1cb5c415); - count = chats.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - chats.get(a).serializeToStream(stream); - } - stream.writeInt32(date); - stream.writeInt32(seq_start); - stream.writeInt32(seq); - } } public static class TL_updatesTooLong extends Updates { public static int constructor = 0xe317af7e; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } } public static class WallPaper extends TLObject { @@ -14226,6 +14196,37 @@ public class TLRPC { } } + public static class TL_channels_messageEditData extends TLObject { + public static int constructor = 0x67e1255f; + + public int flags; + public boolean caption; + + public static TL_channels_messageEditData TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_channels_messageEditData.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_channels_messageEditData", constructor)); + } else { + return null; + } + } + TL_channels_messageEditData result = new TL_channels_messageEditData(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + caption = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = caption ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + } + } + public static class TL_inputEncryptedChat extends TLObject { public static int constructor = 0xf141b5e1; @@ -14326,55 +14327,6 @@ public class TLRPC { } } - public static class InputVideo extends TLObject { - public long id; - public long access_hash; - - public static InputVideo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { - InputVideo result = null; - switch(constructor) { - case 0x5508ec75: - result = new TL_inputVideoEmpty(); - break; - case 0xee579652: - result = new TL_inputVideo(); - break; - } - if (result == null && exception) { - throw new RuntimeException(String.format("can't parse magic %x in InputVideo", constructor)); - } - if (result != null) { - result.readParams(stream, exception); - } - return result; - } - } - - public static class TL_inputVideoEmpty extends InputVideo { - public static int constructor = 0x5508ec75; - - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - } - } - - public static class TL_inputVideo extends InputVideo { - public static int constructor = 0xee579652; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - id = stream.readInt64(exception); - access_hash = stream.readInt64(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(id); - stream.writeInt64(access_hash); - } - } - public static class TL_nearestDc extends TLObject { public static int constructor = 0x8e1a1775; @@ -14685,7 +14637,7 @@ public class TLRPC { } public static class TL_account_passwordInputSettings extends TLObject { - public static int constructor = 0xbcfc532c; + public static int constructor = 0x86916deb; public int flags; public byte[] new_salt; @@ -14746,6 +14698,7 @@ public class TLRPC { public int flags; public boolean ipv6; public boolean media_only; + public boolean tcpo_only; public int id; public String ip_address; public int port; @@ -14767,6 +14720,7 @@ public class TLRPC { flags = stream.readInt32(exception); ipv6 = (flags & 1) != 0; media_only = (flags & 2) != 0; + tcpo_only = (flags & 4) != 0; id = stream.readInt32(exception); ip_address = stream.readString(exception); port = stream.readInt32(exception); @@ -14776,6 +14730,7 @@ public class TLRPC { stream.writeInt32(constructor); flags = ipv6 ? (flags | 1) : (flags &~ 1); flags = media_only ? (flags | 2) : (flags &~ 2); + flags = tcpo_only ? (flags | 4) : (flags &~ 4); stream.writeInt32(flags); stream.writeInt32(id); stream.writeString(ip_address); @@ -15604,21 +15559,6 @@ public class TLRPC { } } - public static class TL_contacts_getSuggested extends TLObject { - public static int constructor = 0xcd773428; - - public int limit; - - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return TL_contacts_suggested.TLdeserialize(stream, constructor, exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(limit); - } - } - public static class TL_contacts_deleteContact extends TLObject { public static int constructor = 0x8e953744; @@ -15780,30 +15720,32 @@ public class TLRPC { } } - public static class TL_messages_getHistory extends TLObject { - public static int constructor = 0x8a8ec2da; + public static class TL_messages_getHistory extends TLObject { + public static int constructor = 0xafa92846; - public InputPeer peer; - public int offset_id; - public int add_offset; - public int limit; - public int max_id; - public int min_id; + public InputPeer peer; + public int offset_id; + public int offset_date; + public int add_offset; + public int limit; + public int max_id; + public int min_id; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return messages_Messages.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - peer.serializeToStream(stream); - stream.writeInt32(offset_id); - stream.writeInt32(add_offset); + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(offset_date); + stream.writeInt32(add_offset); stream.writeInt32(limit); - stream.writeInt32(max_id); - stream.writeInt32(min_id); - } - } + stream.writeInt32(max_id); + stream.writeInt32(min_id); + } + } public static class TL_messages_search extends TLObject { public static int constructor = 0xd4569248; @@ -16013,6 +15955,8 @@ public class TLRPC { public int flags; public boolean no_webpage; public boolean broadcast; + public boolean silent; + public boolean background; public InputPeer peer; public int reply_to_msg_id; public String message; @@ -16028,6 +15972,8 @@ public class TLRPC { stream.writeInt32(constructor); flags = no_webpage ? (flags | 2) : (flags &~ 2); flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); stream.writeInt32(flags); peer.serializeToStream(stream); if ((flags & 1) != 0) { @@ -16054,6 +16000,8 @@ public class TLRPC { public int flags; public boolean broadcast; + public boolean silent; + public boolean background; public InputPeer peer; public int reply_to_msg_id; public InputMedia media; @@ -16067,6 +16015,8 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); stream.writeInt32(flags); peer.serializeToStream(stream); if ((flags & 1) != 0) { @@ -16085,6 +16035,8 @@ public class TLRPC { public int flags; public boolean broadcast; + public boolean silent; + public boolean background; public InputPeer from_peer; public ArrayList id = new ArrayList<>(); public ArrayList random_id = new ArrayList<>(); @@ -16097,6 +16049,8 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); stream.writeInt32(flags); from_peer.serializeToStream(stream); stream.writeInt32(0x1cb5c415); @@ -16997,7 +16951,7 @@ public class TLRPC { public static class TL_account_getPrivacy extends TLObject { public static int constructor = 0xdadbc950; - public TL_inputPrivacyKeyStatusTimestamp key; + public InputPrivacyKey key; public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { return TL_account_privacyRules.TLdeserialize(stream, constructor, exception); @@ -17012,7 +16966,7 @@ public class TLRPC { public static class TL_account_setPrivacy extends TLObject { public static int constructor = 0xc9f81ce8; - public TL_inputPrivacyKeyStatusTimestamp key; + public InputPrivacyKey key; public ArrayList rules = new ArrayList<>(); public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { @@ -17516,6 +17470,8 @@ public class TLRPC { public int flags; public boolean broadcast; + public boolean silent; + public boolean background; public InputPeer peer; public int reply_to_msg_id; public long random_id; @@ -17528,8 +17484,10 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); - flags = broadcast ? (flags | 16) : (flags &~ 16); stream.writeInt32(flags); + flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); peer.serializeToStream(stream); if ((flags & 1) != 0) { stream.writeInt32(reply_to_msg_id); @@ -17632,30 +17590,32 @@ public class TLRPC { } } - public static class TL_channels_getImportantHistory extends TLObject { - public static int constructor = 0xddb929cb; + public static class TL_channels_getImportantHistory extends TLObject { + public static int constructor = 0x8f494bb2; - public InputChannel channel; - public int offset_id; - public int add_offset; - public int limit; - public int max_id; - public int min_id; + public InputChannel channel; + public int offset_id; + public int offset_date; + public int add_offset; + public int limit; + public int max_id; + public int min_id; - public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { - return messages_Messages.TLdeserialize(stream, constructor, exception); - } + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - channel.serializeToStream(stream); - stream.writeInt32(offset_id); - stream.writeInt32(add_offset); - stream.writeInt32(limit); - stream.writeInt32(max_id); - stream.writeInt32(min_id); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(offset_date); + stream.writeInt32(add_offset); + stream.writeInt32(limit); + stream.writeInt32(max_id); + stream.writeInt32(min_id); + } + } public static class TL_channels_readHistory extends TLObject { public static int constructor = 0xcc104937; @@ -18077,8 +18037,245 @@ public class TLRPC { } } + public static class TL_channels_toggleInvites extends TLObject { + public static int constructor = 0x49609307; + + public InputChannel channel; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_channels_exportMessageLink extends TLObject { + public static int constructor = 0xc846d22d; + + public InputChannel channel; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_exportedMessageLink.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(id); + } + } + + public static class TL_channels_toggleSignatures extends TLObject { + public static int constructor = 0x1f69b606; + + public InputChannel channel; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_channels_getMessageEditData extends TLObject { + public static int constructor = 0x27ea3a28; + + public InputChannel channel; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_channels_messageEditData.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(id); + } + } + + public static class TL_channels_editMessage extends TLObject { + public static int constructor = 0xdcda80ed; + + public int flags; + public boolean no_webpage; + public InputChannel channel; + public int id; + public String message; + public ArrayList entities = 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 = no_webpage ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + channel.serializeToStream(stream); + stream.writeInt32(id); + stream.writeString(message); + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + } + //manually created + //MessageMedia start + public static class MessageMedia extends TLObject { + public byte[] bytes; + public Audio audio_unused; + public Photo photo; + public GeoPoint geo; + public String title; + public String address; + public String provider; + public String venue_id; + public Video video_unused; + public Document document; + public String caption; + public String phone_number; + public String first_name; + public String last_name; + public int user_id; + public WebPage webpage; + + public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MessageMedia result = null; + switch(constructor) { + case 0x29632a36: + result = new TL_messageMediaUnsupported_old(); + break; + case 0xc6b68300: + result = new TL_messageMediaAudio_layer45(); + break; + case 0xc8c45a2a: + result = new TL_messageMediaPhoto_old(); + break; + case 0x9f84f49e: + result = new TL_messageMediaUnsupported(); + break; + case 0x3ded6320: + result = new TL_messageMediaEmpty(); + break; + case 0x7912b71f: + result = new TL_messageMediaVenue(); + break; + case 0xa2d24290: + result = new TL_messageMediaVideo_old(); + break; + case 0x2fda2204: + result = new TL_messageMediaDocument_old(); + break; + case 0xf3e02ea8: + result = new TL_messageMediaDocument(); + break; + case 0x5e7d2f39: + result = new TL_messageMediaContact(); + break; + case 0x3d8ce53d: + result = new TL_messageMediaPhoto(); + break; + case 0x5bcf1675: + result = new TL_messageMediaVideo_layer45(); + break; + case 0x56e0d474: + result = new TL_messageMediaGeo(); + break; + case 0xa32dd600: + result = new TL_messageMediaWebPage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MessageMedia", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + if (result.video_unused != null) { + TL_messageMediaDocument mediaDocument = new TL_messageMediaDocument(); + if (result.video_unused instanceof TLRPC.TL_videoEncrypted) { + mediaDocument.document = new TLRPC.TL_documentEncrypted(); + mediaDocument.document.key = result.video_unused.key; + mediaDocument.document.iv = result.video_unused.iv; + } else { + mediaDocument.document = new TLRPC.TL_document(); + } + mediaDocument.document.id = result.video_unused.id; + mediaDocument.document.access_hash = result.video_unused.access_hash; + mediaDocument.document.date = result.video_unused.date; + if (result.video_unused.mime_type != null) { + mediaDocument.document.mime_type = result.video_unused.mime_type; + } else { + mediaDocument.document.mime_type = "video/mp4"; + } + mediaDocument.document.size = result.video_unused.size; + mediaDocument.document.thumb = result.video_unused.thumb; + mediaDocument.document.dc_id = result.video_unused.dc_id; + mediaDocument.caption = result.caption; + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.w = result.video_unused.w; + attributeVideo.h = result.video_unused.h; + attributeVideo.duration = result.video_unused.duration; + mediaDocument.document.attributes.add(attributeVideo); + result = mediaDocument; + if (mediaDocument.caption == null) { + mediaDocument.caption = ""; + } + } else if (result.audio_unused != null) { + TL_messageMediaDocument mediaDocument = new TL_messageMediaDocument(); + if (result.audio_unused instanceof TLRPC.TL_audioEncrypted) { + mediaDocument.document = new TLRPC.TL_documentEncrypted(); + mediaDocument.document.key = result.audio_unused.key; + mediaDocument.document.iv = result.audio_unused.iv; + } else { + mediaDocument.document = new TLRPC.TL_document(); + } + mediaDocument.document.id = result.audio_unused.id; + mediaDocument.document.access_hash = result.audio_unused.access_hash; + mediaDocument.document.date = result.audio_unused.date; + if (result.audio_unused.mime_type != null) { + mediaDocument.document.mime_type = result.audio_unused.mime_type; + } else { + mediaDocument.document.mime_type = "audio/ogg"; + } + mediaDocument.document.size = result.audio_unused.size; + mediaDocument.document.thumb = new TL_photoSizeEmpty(); + mediaDocument.document.thumb.type = "s"; + mediaDocument.document.dc_id = result.audio_unused.dc_id; + mediaDocument.caption = result.caption; + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.duration = result.audio_unused.duration; + attributeAudio.voice = true; + mediaDocument.document.attributes.add(attributeAudio); + result = mediaDocument; + if (mediaDocument.caption == null) { + mediaDocument.caption = ""; + } + } + } + return result; + } + } + //MessageMedia end + //EncryptedChat start public static class EncryptedChat extends TLObject { public int id; @@ -18148,9 +18345,10 @@ public class TLRPC { public Peer to_id; public int date; public MessageAction action; - public Peer fwd_from_id; - public int fwd_date; + //public Peer fwd_from_id; + //public int fwd_date; public int reply_to_msg_id; + public long reply_to_random_id; public String message; public MessageMedia media; public int flags; @@ -18159,8 +18357,13 @@ public class TLRPC { public boolean out; public boolean unread; public ArrayList entities = new ArrayList<>(); + public String via_bot_name; public ReplyMarkup reply_markup; public int views; + public int edit_date; + public boolean silent; + public boolean post; + public TL_messageFwdHeader fwd_from; public int via_bot_id; public int send_state = 0; //custom public int fwd_msg_id = 0; //custom @@ -18188,9 +18391,15 @@ public class TLRPC { case 0xc3060325: result = new TL_message_old4(); break; - case 0xc992e15c: + case 0x555555f9: + result = new TL_message_secret(); + break; + case 0xc09be45f: result = new TL_message(); break; + case 0xc992e15c: + result = new TL_message_layer47(); + break; case 0x5ba66c13: result = new TL_message_old7(); break; @@ -18219,7 +18428,7 @@ public class TLRPC { result = new TL_message_old(); //custom break; case 0x555555F8: - result = new TL_message_secret(); //custom + result = new TL_message_secret_old(); //custom break; case 0xf07814c8: result = new TL_message_old5(); //custom @@ -18284,6 +18493,149 @@ public class TLRPC { } public static class TL_message extends Message { + public static int constructor = 0xc09be45f; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } + if ((flags & 4) != 0) { + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + 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++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + edit_date = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + if (id < 0 && attachPath.startsWith("||")) { + String args[] = attachPath.split("\\|\\|"); + if (args.length > 0) { + params = new HashMap<>(); + for (int a = 1; a < args.length - 1; a++) { + String args2[] = args[a].split("\\|=\\|"); + if (args2.length == 2) { + params.put(args2[0], args2[1]); + } + } + attachPath = args[args.length - 1]; + } + } + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + fwd_from.serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeInt32(via_bot_id); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + if ((flags & 32768) != 0) { + stream.writeInt32(edit_date); + } + String path = attachPath; + if (id < 0 && params != null && params.size() > 0) { + for (HashMap.Entry entry : params.entrySet()) { + path = entry.getKey() + "|=|" + entry.getValue() + "||" + path; + } + path = "||" + path; + } + stream.writeString(path); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_layer47 extends TL_message { public static int constructor = 0xc992e15c; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -18305,10 +18657,16 @@ public class TLRPC { } } if ((flags & 4) != 0) { - fwd_from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + Peer peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (peer instanceof TLRPC.TL_peerChannel) { + fwd_from.channel_id = peer.channel_id; + fwd_from.flags |= 2; + } else if (peer instanceof TLRPC.TL_peerUser) { + fwd_from.from_id = peer.user_id; + fwd_from.flags |= 1; + } + fwd_from.date = stream.readInt32(exception); } if ((flags & 2048) != 0) { via_bot_id = stream.readInt32(exception); @@ -18378,10 +18736,16 @@ public class TLRPC { } to_id.serializeToStream(stream); if ((flags & 4) != 0) { - fwd_from_id.serializeToStream(stream); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + if (fwd_from.from_id != 0) { + TLRPC.TL_peerUser peer = new TL_peerUser(); + peer.user_id = fwd_from.from_id; + peer.serializeToStream(stream); + } else { + TLRPC.TL_peerChannel peer = new TL_peerChannel(); + peer.channel_id = fwd_from.channel_id; + peer.serializeToStream(stream); + } + stream.writeInt32(fwd_from.date); } if ((flags & 2048) != 0) { stream.writeInt32(via_bot_id); @@ -18444,10 +18808,16 @@ public class TLRPC { } } if ((flags & 4) != 0) { - fwd_from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + Peer peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (peer instanceof TLRPC.TL_peerChannel) { + fwd_from.channel_id = peer.channel_id; + fwd_from.flags |= 2; + } else if (peer instanceof TLRPC.TL_peerUser) { + fwd_from.from_id = peer.user_id; + fwd_from.flags |= 1; + } + fwd_from.date = stream.readInt32(exception); } if ((flags & 8) != 0) { reply_to_msg_id = stream.readInt32(exception); @@ -18503,10 +18873,16 @@ public class TLRPC { } to_id.serializeToStream(stream); if ((flags & 4) != 0) { - fwd_from_id.serializeToStream(stream); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + if (fwd_from.from_id != 0) { + TLRPC.TL_peerUser peer = new TL_peerUser(); + peer.user_id = fwd_from.from_id; + peer.serializeToStream(stream); + } else { + TLRPC.TL_peerChannel peer = new TL_peerChannel(); + peer.channel_id = fwd_from.channel_id; + peer.serializeToStream(stream); + } + stream.writeInt32(fwd_from.date); } if ((flags & 8) != 0) { stream.writeInt32(reply_to_msg_id); @@ -18548,9 +18924,10 @@ public class TLRPC { mentioned = (flags & 16) != 0; media_unread = (flags & 32) != 0; id = stream.readInt32(exception); - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - fwd_date = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); date = stream.readInt32(exception); @@ -18573,8 +18950,8 @@ public class TLRPC { flags = media_unread ? (flags | 32) : (flags &~ 32); stream.writeInt32(flags); stream.writeInt32(id); - stream.writeInt32(fwd_from_id.user_id); - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); stream.writeInt32(from_id); to_id.serializeToStream(stream); stream.writeInt32(date); @@ -18601,11 +18978,10 @@ public class TLRPC { from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); if ((flags & 4) != 0) { - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); } if ((flags & 8) != 0) { reply_to_msg_id = stream.readInt32(exception); @@ -18615,7 +18991,7 @@ public class TLRPC { if ((flags & 512) != 0) { media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); } else { - media = new TLRPC.TL_messageMediaEmpty(); + media = new TL_messageMediaEmpty(); } if ((flags & 64) != 0) { reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -18656,10 +19032,8 @@ public class TLRPC { stream.writeInt32(from_id); to_id.serializeToStream(stream); if ((flags & 4) != 0) { - stream.writeInt32(fwd_from_id.user_id); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); } if ((flags & 8) != 0) { stream.writeInt32(reply_to_msg_id); @@ -18700,13 +19074,12 @@ public class TLRPC { id = stream.readInt32(exception); from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - if ((flags & 4) != 0) { - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - } if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); - } + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } if ((flags & 8) != 0) { reply_to_msg_id = stream.readInt32(exception); } @@ -18752,10 +19125,8 @@ public class TLRPC { stream.writeInt32(from_id); to_id.serializeToStream(stream); if ((flags & 4) != 0) { - stream.writeInt32(fwd_from_id.user_id); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); } if ((flags & 8) != 0) { stream.writeInt32(reply_to_msg_id); @@ -18791,18 +19162,20 @@ public class TLRPC { out = (flags & 2) != 0; mentioned = (flags & 16) != 0; media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; id = stream.readInt32(exception); if ((flags & 256) != 0) { from_id = stream.readInt32(exception); } to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - if (from_id == 0) { - if (to_id.user_id != 0) { - from_id = to_id.user_id; - } else { - from_id = -to_id.channel_id; - } - } + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } date = stream.readInt32(exception); action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); } @@ -18813,6 +19186,8 @@ public class TLRPC { flags = out ? (flags | 2) : (flags &~ 2); flags = mentioned ? (flags | 16) : (flags &~ 16); flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 256) != 0) { @@ -18837,13 +19212,12 @@ public class TLRPC { id = stream.readInt32(exception); from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - if ((flags & 4) != 0) { - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); - } + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } if ((flags & 8) != 0) { reply_to_msg_id = stream.readInt32(exception); } @@ -18872,10 +19246,8 @@ public class TLRPC { stream.writeInt32(from_id); to_id.serializeToStream(stream); if ((flags & 4) != 0) { - stream.writeInt32(fwd_from_id.user_id); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); } if ((flags & 8) != 0) { stream.writeInt32(reply_to_msg_id); @@ -18905,13 +19277,12 @@ public class TLRPC { id = stream.readInt32(exception); from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); - if ((flags & 4) != 0) { - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - } - if ((flags & 4) != 0) { - fwd_date = stream.readInt32(exception); - } + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } if ((flags & 8) != 0) { reply_to_msg_id = stream.readInt32(exception); } @@ -18937,10 +19308,8 @@ public class TLRPC { stream.writeInt32(from_id); to_id.serializeToStream(stream); if ((flags & 4) != 0) { - stream.writeInt32(fwd_from_id.user_id); - } - if ((flags & 4) != 0) { - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); } if ((flags & 8) != 0) { stream.writeInt32(reply_to_msg_id); @@ -19026,9 +19395,10 @@ public class TLRPC { public void readParams(AbstractSerializedData stream, boolean exception) { id = stream.readInt32(exception); - fwd_from_id = new TL_peerUser(); - fwd_from_id.user_id = stream.readInt32(exception); - fwd_date = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); from_id = stream.readInt32(exception); to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); out = stream.readBool(exception); @@ -19048,8 +19418,8 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(id); - stream.writeInt32(fwd_from_id.user_id); - stream.writeInt32(fwd_date); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); stream.writeInt32(from_id); to_id.serializeToStream(stream); stream.writeBool(out); @@ -19096,7 +19466,79 @@ public class TLRPC { } } - public static class TL_message_secret extends TL_message { + public static class TL_message_secret extends TL_message { + public static int constructor = 0x555555f9; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + ttl = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), 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++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + if ((flags & 2048) != 0) { + via_bot_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + reply_to_random_id = stream.readInt64(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(ttl); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeString(via_bot_name); + } + if ((flags & 8) != 0) { + stream.writeInt64(reply_to_random_id); + } + stream.writeString(attachPath); + } + } + + public static class TL_message_secret_old extends TL_message_secret { public static int constructor = 0x555555F8; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -19147,6 +19589,7 @@ public class TLRPC { public PeerNotifySettings notify_settings; public int pts; public int last_message_date; //custom + public int last_message_date_i; //custom public long id; //custom public int last_read; //custom @@ -19437,36 +19880,4 @@ public class TLRPC { public static int constructor = 0x1cb5c415; public ArrayList objects = new ArrayList<>(); } - - public static class TL_decryptedMessageHolder extends TLObject { - public static int constructor = 0x555555F9; - - public long random_id; - public int date; - public TL_decryptedMessageLayer layer; - public EncryptedFile file; - public boolean new_key_used; - - public void readParams(AbstractSerializedData stream, boolean exception) { - random_id = stream.readInt64(exception); - date = stream.readInt32(exception); - layer = TL_decryptedMessageLayer.TLdeserialize(stream, stream.readInt32(exception), exception); - if (stream.readBool(exception)) { - file = EncryptedFile.TLdeserialize(stream, stream.readInt32(exception), exception); - } - new_key_used = stream.readBool(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt64(random_id); - stream.writeInt32(date); - layer.serializeToStream(stream); - stream.writeBool(file != null); - if (file != null) { - file.serializeToStream(stream); - } - stream.writeBool(new_key_used); - } - } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java index 97906bc3c..270add2ec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -384,6 +384,7 @@ public class BottomSheet extends Dialog { titleView.setText(title); titleView.setTextColor(0xff757575); titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); titleView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(8)); titleView.setGravity(Gravity.CENTER_VERTICAL); containerView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java index d528b6d9f..b4d8dffe4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -71,6 +71,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { private boolean isDarkTheme; private int botsCount; private boolean loadingBotRecent; + private boolean botRecentLoaded; private String searchingContextUsername; private String searchingContextQuery; @@ -96,7 +97,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } private void loadBotRecent() { - if (loadingBotRecent) { + if (loadingBotRecent || botRecentLoaded) { return; } loadingBotRecent = true; @@ -120,6 +121,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { public void run() { botRecent = users; loadingBotRecent = false; + botRecentLoaded = true; if (lastText != null) { searchUsernameOrHashtag(lastText, lastPosition, messages); } @@ -130,6 +132,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { @Override public void run() { loadingBotRecent = false; + botRecentLoaded = true; } }); } @@ -241,6 +244,10 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { return foundContextBot != null ? foundContextBot.id : 0; } + public String getContextBotName() { + return foundContextBot != null ? foundContextBot.username : ""; + } + private void searchForContextBot(final String username, final String query) { searchResultBotContext = null; searchResultBotContextById = null; @@ -457,7 +464,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { int index = text.indexOf(' '); if (index > 0) { String username = text.substring(1, index); - if (username.length() >= 3) { + if (username.length() >= 1) { for (int a = 1; a < username.length(); a++) { char ch = username.charAt(a); if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) { @@ -488,7 +495,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { char ch = text.charAt(a); if (a == 0 || text.charAt(a - 1) == ' ' || text.charAt(a - 1) == '\n') { if (ch == '@') { - if (needUsernames || botRecent != null && a == 0) { + if (needUsernames || needBotContext && botRecent != null && a == 0) { if (hasIllegalUsernameCharacters) { delegate.needChangePanelVisibility(false); return; @@ -556,7 +563,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { String usernameString = result.toString().toLowerCase(); ArrayList newResult = new ArrayList<>(); final HashMap newResultsHashMap = new HashMap<>(); - if (dogPostion == 0 && botRecent != null) { + if (needBotContext && dogPostion == 0 && botRecent != null) { for (int a = 0; a < botRecent.size(); a++) { TLRPC.User user = botRecent.get(a); if (user.username != null && user.username.length() > 0 && (usernameString.length() > 0 && user.username.toLowerCase().startsWith(usernameString) || usernameString.length() == 0)) { @@ -609,7 +616,8 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } else if (foundType == 1) { ArrayList newResult = new ArrayList<>(); String hashtagString = result.toString().toLowerCase(); - for (HashtagObject hashtagObject : hashtags) { + for (int a = 0; a < hashtags.size(); a++) { + HashtagObject hashtagObject = hashtags.get(a); if (hashtagObject != null && hashtagObject.hashtag != null && hashtagObject.hashtag.startsWith(hashtagString)) { newResult.add(hashtagObject.hashtag); } @@ -711,7 +719,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } public boolean isLongClickEnabled() { - return searchResultHashtags != null; + return searchResultHashtags != null || searchResultCommands != null; } public boolean isBotCommands() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java index 44c9fb4f1..416743649 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java @@ -415,7 +415,7 @@ public class AudioPlayerActivity extends BaseFragment implements NotificationCen private void updateTitle(boolean shutdown) { MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); if (messageObject == null && shutdown || messageObject != null && !messageObject.isMusic()) { - if (!parentLayout.fragmentsStack.isEmpty() && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) == this) { + if (parentLayout != null && !parentLayout.fragmentsStack.isEmpty() && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) == this) { finishFragment(); } else { removeSelfFromStack(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java index 26a696760..aaf4161af 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java @@ -85,7 +85,7 @@ public class AudioSelectActivity extends BaseFragment implements NotificationCen public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("AttachAudio", R.string.AttachAudio)); + actionBar.setTitle(LocaleController.getString("AttachMusic", R.string.AttachMusic)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -243,6 +243,7 @@ public class AudioSelectActivity extends BaseFragment implements NotificationCen attributeAudio.duration = audioEntry.duration; attributeAudio.title = audioEntry.title; attributeAudio.performer = audioEntry.author; + attributeAudio.flags |= 3; message.media.document.attributes.add(attributeAudio); TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java index 6e34ba30a..4339be241 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -241,8 +241,8 @@ public class CacheControlActivity extends BaseFragment { File[] array = file.listFiles(); if (array != null) { for (int b = 0; b < array.length; b++) { + String name = array[b].getName().toLowerCase(); if (documentsMusicType == 1 || documentsMusicType == 2) { - String name = array[b].getName().toLowerCase(); if (name.endsWith(".mp3") || name.endsWith(".m4a")) { if (documentsMusicType == 1) { continue; @@ -251,6 +251,9 @@ public class CacheControlActivity extends BaseFragment { continue; } } + if (name.equals(".nomedia")) { + continue; + } if (array[b].isFile()) { array[b].delete(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java index cd4217d49..9e75d81f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -18,6 +18,7 @@ import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.view.Gravity; import android.view.MotionEvent; import android.widget.FrameLayout; @@ -152,7 +153,11 @@ public class AboutLinkCell extends FrameLayout { } } } else { - pressedLink.onClick(this); + if (pressedLink instanceof URLSpan) { + AndroidUtilities.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } } } catch (Exception e) { FileLog.e("tmessages", e); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java index 78598b5e2..799fa319f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java @@ -18,6 +18,7 @@ import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.view.MotionEvent; import android.view.View; @@ -160,7 +161,11 @@ public class BotHelpCell extends View { } } } else { - pressedLink.onClick(this); + if (pressedLink instanceof URLSpan) { + AndroidUtilities.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } } } catch (Exception e) { FileLog.e("tmessages", e); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java index dc1237c18..0e1040b9a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java @@ -20,25 +20,30 @@ import android.view.SoundEffectConstants; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageLoader; -import org.telegram.messenger.MessagesController; import org.telegram.messenger.SendMessagesHelper; -import org.telegram.messenger.BuildVars; import org.telegram.messenger.FileLoader; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; -import org.telegram.messenger.FileLog; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.Components.ResourceLoader; import org.telegram.ui.Components.SeekBar; +import org.telegram.ui.Components.SeekBarWaveform; import java.io.File; public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelegate { + public interface ChatAudioCellDelegate { + boolean needPlayAudio(MessageObject messageObject); + } + private static TextPaint timePaint; private static Paint circlePaint; + private boolean hasWaveform; private SeekBar seekBar; + private SeekBarWaveform seekBarWaveform; private int seekBarX; private int seekBarY; @@ -50,14 +55,21 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega private StaticLayout timeLayout; private int timeX; - private int timeWidth; + private int timeWidth2; private String lastTimeString = null; + private ChatAudioCellDelegate audioDelegate; + public ChatAudioCell(Context context) { super(context); seekBar = new SeekBar(context); - seekBar.delegate = this; + seekBar.setDelegate(this); + + seekBarWaveform = new SeekBarWaveform(context); + seekBarWaveform.setDelegate(this); + seekBarWaveform.setParentView(this); + radialProgress = new RadialProgress(this); drawForwardedName = true; @@ -85,55 +97,83 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); - boolean result = seekBar.onTouch(event.getAction(), event.getX() - seekBarX, event.getY() - seekBarY); - if (result) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - getParent().requestDisallowInterceptTouchEvent(true); + boolean result = false; + if (delegate.canPerformActions()) { + if (hasWaveform) { + result = seekBarWaveform.onTouch(event.getAction(), event.getX() - seekBarX - AndroidUtilities.dp(13), event.getY() - seekBarY); + } else { + result = seekBar.onTouch(event.getAction(), event.getX() - seekBarX, event.getY() - seekBarY); } - invalidate(); - } else { - int side = AndroidUtilities.dp(36); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { - buttonPressed = true; - invalidate(); - result = true; - radialProgress.swapBackground(getDrawableForCurrentState()); - } - } else if (buttonPressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = false; - playSoundEffect(SoundEffectConstants.CLICK); + if (result) { + if (!hasWaveform && event.getAction() == MotionEvent.ACTION_DOWN) { + getParent().requestDisallowInterceptTouchEvent(true); + } else if (hasWaveform && !seekBarWaveform.isStartDraging() && event.getAction() == MotionEvent.ACTION_UP) { didPressedButton(); - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = false; - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) { + } + invalidate(); + } else { + int side = AndroidUtilities.dp(36); + boolean area; + if (buttonState == 0 || buttonState == 1) { + area = x >= buttonX - AndroidUtilities.dp(12) && x <= buttonX - AndroidUtilities.dp(12) + backgroundWidth && y >= namesOffset && y <= getMeasuredHeight(); + } else { + area = x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side; + } + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (area) { + buttonPressed = true; + invalidate(); + result = true; + radialProgress.swapBackground(getDrawableForCurrentState()); + } + } else if (buttonPressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + buttonPressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + didPressedButton(); + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { buttonPressed = false; invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!area) { + buttonPressed = false; + invalidate(); + } } + radialProgress.swapBackground(getDrawableForCurrentState()); + } + if (result && event.getAction() == MotionEvent.ACTION_DOWN) { + startCheckLongPress(); + } + if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { + cancelCheckLongPress(); + } + if (!result) { + result = super.onTouchEvent(event); } - radialProgress.swapBackground(getDrawableForCurrentState()); - } - if (!result) { - result = super.onTouchEvent(event); } } return result; } + @Override + protected void onLongPress() { + super.onLongPress(); + if (buttonPressed) { + buttonPressed = false; + invalidate(); + } + } + + public void setAudioDelegate(ChatAudioCellDelegate delegate) { + audioDelegate = delegate; + } + private void didPressedButton() { if (buttonState == 0) { - boolean result = MediaController.getInstance().playAudio(currentMessageObject); - if (!currentMessageObject.isOut() && currentMessageObject.isContentUnread()) { - if (currentMessageObject.messageOwner.to_id.channel_id == 0) { - MessagesController.getInstance().markMessageContentAsRead(currentMessageObject.messageOwner); - } - } - if (result) { + if (audioDelegate.needPlayAudio(currentMessageObject)) { buttonState = 1; radialProgress.setBackground(getDrawableForCurrentState(), false, false); invalidate(); @@ -147,12 +187,12 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega } } else if (buttonState == 2) { radialProgress.setProgress(0, false); - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); buttonState = 3; radialProgress.setBackground(getDrawableForCurrentState(), true, false); invalidate(); } else if (buttonState == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.audio); + FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); buttonState = 2; radialProgress.setBackground(getDrawableForCurrentState(), false, false); invalidate(); @@ -170,28 +210,40 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega return; } - if (!seekBar.isDragging()) { - seekBar.setProgress(currentMessageObject.audioProgress); + if (hasWaveform) { + if (!seekBarWaveform.isDragging()) { + seekBarWaveform.setProgress(currentMessageObject.audioProgress); + } + } else { + if (!seekBar.isDragging()) { + seekBar.setProgress(currentMessageObject.audioProgress); + } } - int duration; + int duration = 0; if (!MediaController.getInstance().isPlayingAudio(currentMessageObject)) { - duration = currentMessageObject.messageOwner.media.audio.duration; + for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } } else { duration = currentMessageObject.audioProgressSec; } String timeString = String.format("%02d:%02d", duration / 60, duration % 60); if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) { lastTimeString = timeString; - timeWidth = (int)Math.ceil(timePaint.measureText(timeString)); - timeLayout = new StaticLayout(timeString, timePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + timeWidth2 = (int)Math.ceil(timePaint.measureText(timeString)); + timeLayout = new StaticLayout(timeString, timePaint, timeWidth2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } invalidate(); } public void downloadAudioIfNeed() { if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); buttonState = 3; radialProgress.setBackground(getDrawableForCurrentState(), false, false); } @@ -221,9 +273,6 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega if (cacheFile == null) { cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } - if (BuildVars.DEBUG_VERSION) { - FileLog.d("tmessages", "looking for audio in " + cacheFile); - } if (cacheFile.exists()) { MediaController.getInstance().removeLoadingFileObserver(this); boolean playing = MediaController.getInstance().isPlayingAudio(currentMessageObject); @@ -264,6 +313,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega @Override public void onSuccessDownload(String fileName) { updateButtonState(true); + updateWaveform(); } @Override @@ -303,7 +353,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(13); timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(66); } else { - if (isChat && currentMessageObject.messageOwner.from_id > 0) { + if (isChat && currentMessageObject.isFromUser()) { seekBarX = AndroidUtilities.dp(116); buttonX = AndroidUtilities.dp(74); timeX = AndroidUtilities.dp(127); @@ -313,9 +363,9 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega timeX = AndroidUtilities.dp(75); } } - - seekBar.width = backgroundWidth - AndroidUtilities.dp(70); - seekBar.height = AndroidUtilities.dp(30); + seekBarWaveform.width = seekBar.width = backgroundWidth - AndroidUtilities.dp(70); + seekBarWaveform.height = seekBar.height = AndroidUtilities.dp(30); + seekBarWaveform.width -= AndroidUtilities.dp(20); seekBarY = AndroidUtilities.dp(11) + namesOffset; buttonY = AndroidUtilities.dp(13) + namesOffset; radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(40), buttonY + AndroidUtilities.dp(40)); @@ -328,28 +378,51 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega boolean dataChanged = currentMessageObject == messageObject && isUserDataChanged(); if (currentMessageObject != messageObject || dataChanged) { if (AndroidUtilities.isTablet()) { - backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(300)); } else { - backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(300)); } - if (messageObject.isOutOwner()) { - seekBar.type = 0; - } else { - seekBar.type = 1; + int duration = 0; + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } } + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(75 + 14) - (int) Math.ceil(timePaint.measureText("00:00")); + measureTime(messageObject); + int minSize = AndroidUtilities.dp(40 + 14 + 20 + 90 + 10) + timeWidth; + backgroundWidth = Math.min(backgroundWidth, minSize + duration * AndroidUtilities.dp(10)); + + hasWaveform = false; + if (messageObject.isOutOwner()) { + seekBarWaveform.setColors(0xffc3e3ab, 0xff87bf78, 0xffa9d389); + } else { + seekBarWaveform.setColors(0xffdee5eb, 0xff4195e5, 0xffaed5e2); + } + seekBar.type = messageObject.isOutOwner() ? 0 : 1; + super.setMessageObject(messageObject); } + updateWaveform(); updateButtonState(dataChanged); } + @Override + protected int getMaxNameWidth() { + return backgroundWidth - AndroidUtilities.dp(24); + } + @Override public void setCheckPressed(boolean value, boolean pressed) { super.setCheckPressed(value, pressed); if (radialProgress.swapBackground(getDrawableForCurrentState())) { invalidate(); } + seekBarWaveform.setSelected(isDrawSelectedBackground()); } @Override @@ -358,6 +431,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega if (radialProgress.swapBackground(getDrawableForCurrentState())) { invalidate(); } + seekBarWaveform.setSelected(isDrawSelectedBackground()); } @Override @@ -366,12 +440,29 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega if (radialProgress.swapBackground(getDrawableForCurrentState())) { invalidate(); } + seekBarWaveform.setSelected(isDrawSelectedBackground()); } private Drawable getDrawableForCurrentState() { return ResourceLoader.audioStatesDrawable[currentMessageObject.isOutOwner() ? buttonState : buttonState + 5][isDrawSelectedBackground() ? 2 : (buttonPressed ? 1 : 0)]; } + private void updateWaveform() { + File path = FileLoader.getPathToMessage(currentMessageObject.messageOwner); + for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.waveform == null || attribute.waveform.length == 0) { + MediaController.getInstance().generateWaveform(currentMessageObject); + } + hasWaveform = attribute.waveform != null; + seekBarWaveform.setWaveform(attribute.waveform); + seekBarWaveform.setMessageObject(currentMessageObject); + break; + } + } + } + @Override protected void onDraw(Canvas canvas) { if (currentMessageObject == null) { @@ -381,8 +472,13 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega super.onDraw(canvas); canvas.save(); - canvas.translate(seekBarX, seekBarY); - seekBar.draw(canvas); + if (hasWaveform) { + canvas.translate(seekBarX + AndroidUtilities.dp(13), seekBarY); + seekBarWaveform.draw(canvas); + } else { + canvas.translate(seekBarX, seekBarY); + seekBar.draw(canvas); + } canvas.restore(); radialProgress.setProgressColor(currentMessageObject.isOutOwner() ? 0xff87bf78 : (isDrawSelectedBackground() ? 0xff83b2c2 : 0xffa2b5c7)); @@ -396,7 +492,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega canvas.restore(); if (currentMessageObject.messageOwner.to_id.channel_id == 0 && currentMessageObject.isContentUnread()) { - canvas.drawCircle(timeX + timeWidth + AndroidUtilities.dp(8), AndroidUtilities.dp(49.5f) + namesOffset, AndroidUtilities.dp(3), circlePaint); + canvas.drawCircle(timeX + timeWidth2 + AndroidUtilities.dp(8), AndroidUtilities.dp(49.5f) + namesOffset, AndroidUtilities.dp(3), circlePaint); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 6c0ab5d8c..ed1b12906 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -25,6 +25,7 @@ import android.view.MotionEvent; import android.view.SoundEffectConstants; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; @@ -47,8 +48,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo public interface ChatBaseCellDelegate { void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user); - void didPressedViaBot(ChatBaseCell cell, TLRPC.User user); - void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat); + void didPressedViaBot(ChatBaseCell cell, String username); + void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId); void didPressedCancelSendButton(ChatBaseCell cell); void didLongPressed(ChatBaseCell cell); void didPressReplyMessage(ChatBaseCell cell, int id); @@ -78,6 +79,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo protected MessageObject currentMessageObject; private int viaWidth; private int viaNameWidth; + protected int availableTimeWidth; private static TextPaint timePaint; private static TextPaint namePaint; @@ -110,7 +112,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo private boolean replyPressed; private TLRPC.FileLocation currentReplyPhoto; - private boolean drawShareButton; + protected boolean drawShareButton; private boolean sharePressed; private int shareStartX; private int shareStartY; @@ -255,10 +257,12 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo TLRPC.User newUser = null; TLRPC.Chat newChat = null; - if (currentMessageObject.messageOwner.from_id > 0) { + if (currentMessageObject.isFromUser()) { newUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); } else if (currentMessageObject.messageOwner.from_id < 0) { newChat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); + } else if (currentMessageObject.messageOwner.post) { + newChat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); } TLRPC.FileLocation newPhoto = null; @@ -312,12 +316,52 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } protected void measureTime(MessageObject messageObject) { - currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + boolean hasSign = !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 && messageObject.messageOwner.post; + TLRPC.User signUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + if (hasSign && signUser == null) { + hasSign = false; + } + if (hasSign) { + currentTimeString = ", " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + } else { + currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + } timeTextWidth = timeWidth = (int) Math.ceil(timePaint.measureText(currentTimeString)); if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); - timeWidth += (int) Math.ceil(timePaint.measureText(currentViewsString)) + ResourceLoader.viewsCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); + viewsTextWidth = (int) Math.ceil(timePaint.measureText(currentViewsString)); + timeWidth += viewsTextWidth + ResourceLoader.viewsCountDrawable[0].getIntrinsicWidth() + AndroidUtilities.dp(10); } + if (hasSign) { + if (availableTimeWidth == 0) { + availableTimeWidth = AndroidUtilities.dp(100); + } + CharSequence name = ContactsController.formatName(signUser.first_name, signUser.last_name).replace('\n', ' '); + int widthForSign = availableTimeWidth - timeWidth; + int width = (int) Math.ceil(timePaint.measureText(name, 0, name.length())); + if (width > widthForSign) { + name = TextUtils.ellipsize(name, timePaint, widthForSign, TextUtils.TruncateAt.END); + width = widthForSign; + } + currentTimeString = name + currentTimeString; + timeTextWidth += width; + timeWidth += width; + } + } + + protected boolean checkNeedDrawShareButton(MessageObject messageObject) { + if (messageObject.isFromUser()) { + TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + if (user != null && user.bot && messageObject.type != 13 && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty || messageObject.messageOwner.media == null + || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && !(messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage))) { + return true; + } + } else if (messageObject.messageOwner.from_id < 0 || messageObject.messageOwner.post) { + if (messageObject.messageOwner.to_id.channel_id != 0 && (messageObject.messageOwner.reply_to_msg_id == 0 || messageObject.type != 13)) { + return true; + } + } + return false; } public void setMessageObject(MessageObject messageObject) { @@ -329,7 +373,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo isCheckPressed = true; isAvatarVisible = false; wasLayout = false; - drawShareButton = false; + drawShareButton = checkNeedDrawShareButton(messageObject); replyNameLayout = null; replyTextLayout = null; replyNameWidth = 0; @@ -351,15 +395,15 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } } - if (messageObject.messageOwner.from_id > 0) { - currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); - } else if (messageObject.messageOwner.from_id < 0) { - currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); - if (messageObject.messageOwner.to_id.channel_id != 0 && (messageObject.messageOwner.reply_to_msg_id == 0 || messageObject.type != 13)) { - drawShareButton = true; - } + if (currentMessageObject.isFromUser()) { + currentUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); + } else if (currentMessageObject.messageOwner.from_id < 0) { + currentChat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); + } else if (currentMessageObject.messageOwner.post) { + currentChat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); } - if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { + + if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { isAvatarVisible = true; if (currentUser != null) { if (currentUser.photo != null) { @@ -382,13 +426,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo avatarImage.setImage(currentPhoto, "50_50", avatarDrawable, null, false); } - currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); - timeTextWidth = timeWidth = (int)Math.ceil(timePaint.measureText(currentTimeString)); - if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { - currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); - viewsTextWidth = (int) Math.ceil(timePaint.measureText(currentViewsString)); - timeWidth += viewsTextWidth + ResourceLoader.viewsCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); - } + + measureTime(messageObject); namesOffset = 0; @@ -402,10 +441,14 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo viaWidth = (int) Math.ceil(forwardNamePaint.measureText(viaString)); currentViaBotUser = botUser; } + } else if (messageObject.messageOwner.via_bot_name != null && messageObject.messageOwner.via_bot_name.length() > 0) { + viaUsername = "@" + messageObject.messageOwner.via_bot_name; + viaString = " via " + messageObject.messageOwner.via_bot_name; + viaWidth = (int) Math.ceil(forwardNamePaint.measureText(viaString)); } boolean authorName = drawName && isChat && !currentMessageObject.isOutOwner(); - boolean viaBot = messageObject.messageOwner.fwd_from_id == null && currentViaBotUser != null; + boolean viaBot = messageObject.messageOwner.fwd_from == null && viaUsername != null; if (authorName || viaBot) { drawName = true; nameWidth = getMaxNameWidth(); @@ -413,7 +456,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo nameWidth = AndroidUtilities.dp(100); } - if (authorName || !currentMessageObject.isOutOwner()) { + if (authorName) { if (currentUser != null) { currentNameString = UserObject.getUserName(currentUser); } else if (currentChat != null) { @@ -432,12 +475,12 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo viaNameWidth += AndroidUtilities.dp(4); } if (currentNameString.length() > 0) { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s via @%s", nameStringFinal, currentViaBotUser.username)); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s via %s", nameStringFinal, viaUsername)); stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), nameStringFinal.length() + 1, nameStringFinal.length() + 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), nameStringFinal.length() + 5, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; } else { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("via @%s", currentViaBotUser.username)); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("via %s", viaUsername)); stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), 4, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; @@ -462,19 +505,24 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } if (drawForwardedName && messageObject.isForwarded()) { - if (messageObject.messageOwner.fwd_from_id instanceof TLRPC.TL_peerChannel) { - currentForwardChannel = MessagesController.getInstance().getChat(messageObject.messageOwner.fwd_from_id.channel_id); - currentForwardUser = null; - } else if (messageObject.messageOwner.fwd_from_id instanceof TLRPC.TL_peerUser) { - currentForwardChannel = null; - currentForwardUser = MessagesController.getInstance().getUser(messageObject.messageOwner.fwd_from_id.user_id); + currentForwardUser = null; + currentForwardChannel = null; + if (messageObject.messageOwner.fwd_from.channel_id != 0) { + currentForwardChannel = MessagesController.getInstance().getChat(messageObject.messageOwner.fwd_from.channel_id); + } + if (messageObject.messageOwner.fwd_from.from_id != 0) { + currentForwardUser = MessagesController.getInstance().getUser(messageObject.messageOwner.fwd_from.from_id); } if (currentForwardUser != null || currentForwardChannel != null) { - if (currentForwardUser != null) { + if (currentForwardChannel != null) { + if (currentForwardUser != null) { + currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser)); + } else { + currentForwardNameString = currentForwardChannel.title; + } + } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); - } else { - currentForwardNameString = currentForwardChannel.title; } forwardedNameWidth = getMaxNameWidth(); @@ -537,7 +585,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (messageObject.isOutOwner()) { maxWidth = width - backgroundWidth - AndroidUtilities.dp(60); } else { - maxWidth = width - backgroundWidth - AndroidUtilities.dp(56 + (isChat && messageObject.messageOwner.from_id > 0 ? 61 : 0)); + maxWidth = width - backgroundWidth - AndroidUtilities.dp(56 + (isChat && messageObject.isFromUser() ? 61 : 0)); } } else { maxWidth = getMaxNameWidth() - AndroidUtilities.dp(22); @@ -550,7 +598,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo CharSequence stringFinalText = null; if (messageObject.replyMessageObject != null) { TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs, 80); - if (photoSize == null || messageObject.replyMessageObject.type == 13 || messageObject.type == 13 && !AndroidUtilities.isTablet()) { + if (photoSize == null || messageObject.replyMessageObject.type == 13 || messageObject.type == 13 && !AndroidUtilities.isTablet() || messageObject.replyMessageObject.isSecretMedia()) { replyImageReceiver.setImageBitmap((Drawable) null); needReplyImage = false; } else { @@ -561,16 +609,21 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } String name = null; - if (messageObject.replyMessageObject.messageOwner.from_id > 0) { + if (messageObject.replyMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(messageObject.replyMessageObject.messageOwner.from_id); if (user != null) { name = UserObject.getUserName(user); } - } else { + } else if (messageObject.replyMessageObject.messageOwner.from_id < 0) { TLRPC.Chat chat = MessagesController.getInstance().getChat(-messageObject.replyMessageObject.messageOwner.from_id); if (chat != null) { name = chat.title; } + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageObject.replyMessageObject.messageOwner.to_id.channel_id); + if (chat != null) { + name = chat.title; + } } if (name != null) { @@ -666,7 +719,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (currentUser != null) { delegate.didPressedUserAvatar(this, currentUser); } else if (currentChat != null) { - delegate.didPressedChannelAvatar(this, currentChat); + delegate.didPressedChannelAvatar(this, currentChat, 0); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -681,10 +734,10 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo forwardNamePressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (currentForwardUser != null) { + if (currentForwardChannel != null) { + delegate.didPressedChannelAvatar(this, currentForwardChannel, currentMessageObject.messageOwner.fwd_from.channel_post); + } else if (currentForwardUser != null) { delegate.didPressedUserAvatar(this, currentForwardUser); - } else { - delegate.didPressedChannelAvatar(this, currentForwardChannel); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -699,7 +752,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressedViaBot(this, currentViaBotUser); + delegate.didPressedViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardBotPressed = false; @@ -763,13 +816,13 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (!media) { if (!currentMessageObject.isOutOwner()) { - timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0); } else { timeX = layoutWidth - timeWidth - AndroidUtilities.dp(38.5f); } } else { if (!currentMessageObject.isOutOwner()) { - timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0); } else { timeX = layoutWidth - timeWidth - AndroidUtilities.dp(42.0f); } @@ -863,7 +916,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableIn; } } - if (isChat && currentMessageObject.messageOwner.from_id > 0) { + if (isChat && currentMessageObject.isFromUser()) { setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(52 + (!media ? 0 : 9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); } else { setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); @@ -1012,7 +1065,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo ResourceLoader.errorDrawable.draw(canvas); } } else { - Drawable countDrawable = ResourceLoader.viewsMediaCountDrawable[isDrawSelectedBackground() ? 1 : 0]; + Drawable countDrawable = ResourceLoader.viewsMediaCountDrawable; setDrawableBounds(countDrawable, timeX, layoutHeight - AndroidUtilities.dp(10) - timeLayout.getHeight()); countDrawable.draw(canvas); @@ -1047,8 +1100,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } } else { if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(ResourceLoader.viewsCountDrawable, timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); - ResourceLoader.viewsCountDrawable.draw(canvas); + setDrawableBounds(ResourceLoader.viewsCountDrawable[isDrawSelectedBackground() ? 1 : 0], timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); + ResourceLoader.viewsCountDrawable[isDrawSelectedBackground() ? 1 : 0].draw(canvas); } else { setDrawableBounds(ResourceLoader.viewsOutCountDrawable, timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); ResourceLoader.viewsOutCountDrawable.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java index e5335ff54..f204795d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java @@ -112,7 +112,7 @@ public class ChatContactCell extends ChatBaseCell { if (x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(42) && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight()) { avatarPressed = true; result = true; - } else if (x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) + namesOffset && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52) + namesOffset) { + } else if (drawAddButton && x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) + namesOffset && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52) + namesOffset) { buttonPressed = true; result = true; } @@ -196,7 +196,20 @@ public class ChatContactCell extends ChatBaseCell { } avatarImage.setImage(currentPhoto, "50_50", avatarDrawable, null, false); + String phone = messageObject.messageOwner.media.phone_number; + if (phone != null && phone.length() != 0) { + if (!phone.startsWith("+")) { + phone = "+" + phone; + } + phone = PhoneFormat.getInstance().format(phone); + } else { + phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); + } + String currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name); + if (currentNameString.length() == 0) { + currentNameString = phone; + } int nameWidth = Math.min((int) Math.ceil(namePaint.measureText(currentNameString)), maxWidth); if (maxWidth < 0) { maxWidth = AndroidUtilities.dp(100); @@ -210,15 +223,7 @@ public class ChatContactCell extends ChatBaseCell { nameWidth = 0; } - String phone = messageObject.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (!phone.startsWith("+")) { - phone = "+" + phone; - } - phone = PhoneFormat.getInstance().format(phone); - } else { - phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); - } + int phoneWidth = Math.min((int) Math.ceil(phonePaint.measureText(phone)), maxWidth); stringFinal = TextUtils.ellipsize(phone.replace("\n", " "), phonePaint, phoneWidth, TextUtils.TruncateAt.END); phoneLayout = new StaticLayout(stringFinal, phonePaint, phoneWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); @@ -230,6 +235,7 @@ public class ChatContactCell extends ChatBaseCell { namesWidth = Math.max(nameWidth, phoneWidth); backgroundWidth = AndroidUtilities.dp(77 + (drawAddButton ? 42 : 0)) + namesWidth; + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(29); super.setMessageObject(messageObject); } @@ -237,7 +243,7 @@ public class ChatContactCell extends ChatBaseCell { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(71) + namesOffset); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(75) + namesOffset); } @Override @@ -253,7 +259,7 @@ public class ChatContactCell extends ChatBaseCell { if (currentMessageObject.isOutOwner()) { x = layoutWidth - backgroundWidth + AndroidUtilities.dp(8); } else { - if (isChat && currentMessageObject.messageOwner.from_id > 0) { + if (isChat && currentMessageObject.isFromUser()) { x = AndroidUtilities.dp(69); } else { x = AndroidUtilities.dp(16); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index 1b92ebd7c..8f4e8a54c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -21,6 +21,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.view.MotionEvent; import android.view.SoundEffectConstants; @@ -39,6 +40,7 @@ import org.telegram.ui.Components.RadialProgress; import org.telegram.ui.Components.ResourceLoader; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.URLSpanBotCommand; +import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.PhotoViewer; import org.telegram.messenger.ImageReceiver; @@ -417,7 +419,7 @@ public class ChatMediaCell extends ChatBaseCell { } else if (currentMessageObject.type == 9) { FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, false, false); } else if (currentMessageObject.type == 3) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); } buttonState = 1; radialProgress.setBackground(getDrawableForCurrentState(), true, animated); @@ -431,10 +433,8 @@ public class ChatMediaCell extends ChatBaseCell { cancelLoading = true; if (currentMessageObject.type == 1 || currentMessageObject.type == 8) { photoImage.cancelLoadImage(); - } else if (currentMessageObject.type == 9) { + } else if (currentMessageObject.type == 9 || currentMessageObject.type == 3) { FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); - } else if (currentMessageObject.type == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video); } buttonState = 0; radialProgress.setBackground(getDrawableForCurrentState(), false, animated); @@ -475,12 +475,23 @@ public class ChatMediaCell extends ChatBaseCell { return false; } + @Override + protected void onLongPress() { + if (pressedLink instanceof URLSpanNoUnderline) { + + } else if (pressedLink instanceof URLSpan) { + delegate.didPressUrl(currentMessageObject, pressedLink, true); + return; + } + super.onLongPress(); + } + @Override public void setMessageObject(MessageObject messageObject) { boolean messageChanged = currentMessageObject != messageObject; boolean dataChanged = currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet); if (currentMessageObject != messageObject || isPhotoDataChanged(messageObject) || dataChanged) { - drawForwardedName = messageObject.messageOwner.fwd_from_id != null && messageObject.type != 13; + drawForwardedName = messageObject.messageOwner.fwd_from != null && messageObject.type != 13; media = messageObject.type != 9; cancelLoading = false; additionHeight = 0; @@ -510,14 +521,24 @@ public class ChatMediaCell extends ChatBaseCell { } else { maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122 + 86 + 24); } + if (checkNeedDrawShareButton(messageObject)) { + maxWidth -= AndroidUtilities.dp(20); + } if (currentNameString == null || !currentNameString.equals(name)) { currentNameString = name; - nameLayout = StaticLayoutEx.createStaticLayout(currentNameString, namePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1); + nameLayout = StaticLayoutEx.createStaticLayout(currentNameString, namePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.MIDDLE, maxWidth, 3); + nameOffsetX = Integer.MIN_VALUE; if (nameLayout != null && nameLayout.getLineCount() > 0) { - nameWidth = Math.min(maxWidth, (int) Math.ceil(nameLayout.getLineWidth(0))); - nameOffsetX = (int) Math.ceil(-nameLayout.getLineLeft(0)); + int maxLineWidth = 0; + int maxLeft = 0; + for (int a = 0; a < nameLayout.getLineCount(); a++) { + maxLineWidth = Math.max(maxLineWidth, (int) Math.ceil(nameLayout.getLineWidth(a))); + nameOffsetX = Math.max(maxLeft, (int) Math.ceil(-nameLayout.getLineLeft(a))); + } + nameWidth = Math.min(maxWidth, maxLineWidth); } else { nameWidth = maxWidth; + nameOffsetX = 0; } } @@ -528,7 +549,14 @@ public class ChatMediaCell extends ChatBaseCell { infoOffset = 0; infoWidth = Math.min(maxWidth, (int) Math.ceil(infoPaint.measureText(currentInfoString))); CharSequence str2 = TextUtils.ellipsize(currentInfoString, infoPaint, infoWidth, TextUtils.TruncateAt.END); - infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + try { + if (infoWidth < 0) { + infoWidth = AndroidUtilities.dp(10); + } + infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } } else if (messageObject.type == 8) { String str = AndroidUtilities.formatFileSize(messageObject.messageOwner.media.document.size); @@ -541,10 +569,17 @@ public class ChatMediaCell extends ChatBaseCell { nameLayout = null; currentNameString = null; } else if (messageObject.type == 3) { - int duration = messageObject.messageOwner.media.video.duration; + int duration = 0; + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } int minutes = duration / 60; int seconds = duration - minutes * 60; - String str = String.format("%d:%02d, %s", minutes, seconds, AndroidUtilities.formatFileSize(messageObject.messageOwner.media.video.size)); + String str = String.format("%d:%02d, %s", minutes, seconds, AndroidUtilities.formatFileSize(messageObject.messageOwner.media.document.size)); if (currentInfoString == null || !currentInfoString.equals(str)) { currentInfoString = str; infoOffset = ResourceLoader.videoIconDrawable.getIntrinsicWidth() + AndroidUtilities.dp(4); @@ -560,10 +595,11 @@ public class ChatMediaCell extends ChatBaseCell { nameLayout = null; updateSecretTimeText(messageObject); } - if (messageObject.type == 9) { //doc + if (messageObject.type == 9) { photoWidth = AndroidUtilities.dp(86); photoHeight = AndroidUtilities.dp(86); - backgroundWidth = photoWidth + Math.max(nameWidth, infoWidth) + AndroidUtilities.dp(68); + availableTimeWidth = Math.max(nameWidth, infoWidth) + AndroidUtilities.dp(37); + backgroundWidth = photoWidth + availableTimeWidth + AndroidUtilities.dp(31); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); photoImage.setNeedsQualityThumb(true); photoImage.setShouldGenerateQualityThumb(true); @@ -589,6 +625,7 @@ public class ChatMediaCell extends ChatBaseCell { } media = false; + availableTimeWidth = maxWidth - AndroidUtilities.dp(7); measureTime(messageObject); photoWidth = AndroidUtilities.dp(86); photoHeight = AndroidUtilities.dp(86); @@ -604,6 +641,7 @@ public class ChatMediaCell extends ChatBaseCell { backgroundWidth = photoWidth + AndroidUtilities.dp(21) + maxWidth; currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=72x72&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); } else { + availableTimeWidth = AndroidUtilities.dp(200 - 14); photoWidth = AndroidUtilities.dp(200); photoHeight = AndroidUtilities.dp(100); backgroundWidth = photoWidth + AndroidUtilities.dp(12); @@ -643,6 +681,7 @@ public class ChatMediaCell extends ChatBaseCell { photoHeight *= maxWidth / photoWidth; photoWidth = (int) maxWidth; } + availableTimeWidth = photoWidth - AndroidUtilities.dp(14); backgroundWidth = photoWidth + AndroidUtilities.dp(12); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); photoImage.setNeedsQualityThumb(false); @@ -667,10 +706,11 @@ public class ChatMediaCell extends ChatBaseCell { messageObject.messageOwner.media.document.size, "webp", true); } } else { + int maxPhotoWidth; if (AndroidUtilities.isTablet()) { - photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + maxPhotoWidth = photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); } else { - photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + maxPhotoWidth = photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); } photoHeight = photoWidth + AndroidUtilities.dp(100); @@ -767,6 +807,7 @@ public class ChatMediaCell extends ChatBaseCell { w = h = AndroidUtilities.dp(100); } + availableTimeWidth = maxPhotoWidth - AndroidUtilities.dp(14); measureTime(messageObject); int timeWidthTotal = timeWidth + AndroidUtilities.dp(14 + (messageObject.isOutOwner() ? 20 : 0)); if (w < timeWidthTotal) { @@ -1022,7 +1063,7 @@ public class ChatMediaCell extends ChatBaseCell { x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); } } else { - if (isChat && currentMessageObject.messageOwner.from_id > 0) { + if (isChat && currentMessageObject.isFromUser()) { x = AndroidUtilities.dp(67); } else { x = AndroidUtilities.dp(15); @@ -1218,11 +1259,15 @@ public class ChatMediaCell extends ChatBaseCell { nameLayout.draw(canvas); canvas.restore(); - if (infoLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(30)); - infoLayout.draw(canvas); - canvas.restore(); + try { + if (infoLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + nameLayout.getLineBottom(nameLayout.getLineCount() - 1) + AndroidUtilities.dp(10)); + infoLayout.draw(canvas); + canvas.restore(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); } } } 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 575e04cd3..b07d425a9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -9,13 +9,10 @@ package org.telegram.ui.Cells; import android.content.Context; -import android.content.Intent; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; -import android.provider.Browser; import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -23,6 +20,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.ViewStructure; @@ -218,7 +216,11 @@ public class ChatMessageCell extends ChatBaseCell { } else if (linkPreviewPressed) { try { if (pressedLink != null) { - pressedLink.onClick(this); + if (pressedLink instanceof URLSpan) { + AndroidUtilities.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } } else { if (drawImageButton && delegate != null) { if (isGifDocument) { @@ -243,10 +245,7 @@ public class ChatMessageCell extends ChatBaseCell { if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { delegate.needOpenWebView(webPage.embed_url, webPage.site_name, webPage.url, webPage.embed_width, webPage.embed_height); } else { - Uri uri = Uri.parse(webPage.url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName()); - getContext().startActivity(intent); + AndroidUtilities.openUrl(getContext(), webPage.url); } } } @@ -388,6 +387,9 @@ public class ChatMessageCell extends ChatBaseCell { delegate.didPressUrl(currentMessageObject, pressedLink, true); return; } + } else if (pressedLink instanceof URLSpan) { + delegate.didPressUrl(currentMessageObject, pressedLink, true); + return; } super.onLongPress(); } @@ -420,7 +422,7 @@ public class ChatMessageCell extends ChatBaseCell { int maxWidth; if (AndroidUtilities.isTablet()) { - if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { + if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); drawName = true; } else { @@ -428,7 +430,7 @@ public class ChatMessageCell extends ChatBaseCell { maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); } } else { - if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { + if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); drawName = true; } else { @@ -438,6 +440,7 @@ public class ChatMessageCell extends ChatBaseCell { } backgroundWidth = maxWidth; + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(29); super.setMessageObject(messageObject); @@ -458,18 +461,21 @@ public class ChatMessageCell extends ChatBaseCell { if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage) { int linkPreviewMaxWidth; if (AndroidUtilities.isTablet()) { - if (messageObject.messageOwner.from_id > 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOut()) { + if (messageObject.isFromUser() && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOut()) { linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); } else { linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); } } else { - if (messageObject.messageOwner.from_id > 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOutOwner()) { + if (messageObject.isFromUser() && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOutOwner()) { linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); } else { linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); } } + if (drawShareButton) { + linkPreviewMaxWidth -= AndroidUtilities.dp(20); + } TLRPC.TL_webPage webPage = (TLRPC.TL_webPage) messageObject.messageOwner.media.webpage; @@ -791,6 +797,7 @@ public class ChatMessageCell extends ChatBaseCell { if (hasLinkPreview || maxWidth - messageObject.lastLineWidth < timeMore) { totalHeight += AndroidUtilities.dp(14); backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(29); + backgroundWidth = Math.max(backgroundWidth, timeWidth + AndroidUtilities.dp(29)); } else { int diff = maxChildWidth - messageObject.lastLineWidth; if (diff >= 0 && diff <= timeMore) { @@ -816,7 +823,7 @@ public class ChatMessageCell extends ChatBaseCell { textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); textY = AndroidUtilities.dp(10) + namesOffset; } else { - textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); + textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0); textY = AndroidUtilities.dp(10) + namesOffset; } } @@ -832,7 +839,7 @@ public class ChatMessageCell extends ChatBaseCell { textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); textY = AndroidUtilities.dp(10) + namesOffset; } else { - textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); + textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0); textY = AndroidUtilities.dp(10) + namesOffset; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMusicCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMusicCell.java index 1f1c0d9f5..0404682d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMusicCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMusicCell.java @@ -68,7 +68,7 @@ public class ChatMusicCell extends ChatBaseCell implements SeekBar.SeekBarDelega super(context); seekBar = new SeekBar(context); - seekBar.delegate = this; + seekBar.setDelegate(this); radialProgress = new RadialProgress(this); drawForwardedName = false; @@ -194,7 +194,8 @@ public class ChatMusicCell extends ChatBaseCell implements SeekBar.SeekBarDelega int duration = 0; int currentProgress = 0; - for (TLRPC.DocumentAttribute attribute : currentMessageObject.messageOwner.media.document.attributes) { + for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeAudio) { duration = attribute.duration; break; @@ -323,7 +324,7 @@ public class ChatMusicCell extends ChatBaseCell implements SeekBar.SeekBarDelega buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(13); timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(63); } else { - if (isChat && currentMessageObject.messageOwner.from_id > 0) { + if (isChat && currentMessageObject.isFromUser()) { seekBarX = AndroidUtilities.dp(113); buttonX = AndroidUtilities.dp(74); timeX = AndroidUtilities.dp(124); @@ -348,9 +349,9 @@ public class ChatMusicCell extends ChatBaseCell implements SeekBar.SeekBarDelega boolean dataChanged = currentMessageObject == messageObject && isUserDataChanged(); if (currentMessageObject != messageObject || dataChanged) { if (AndroidUtilities.isTablet()) { - backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(300)); } else { - backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(300)); } if (messageObject.isOutOwner()) { @@ -375,6 +376,16 @@ public class ChatMusicCell extends ChatBaseCell implements SeekBar.SeekBarDelega authorX = -(int) Math.ceil(authorLayout.getLineLeft(0)); } + int duration = 0; + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(72 + 14) - (int) Math.ceil(timePaint.measureText(String.format("%d:%02d / %d:%02d", duration / 60, duration % 60, duration / 60, duration % 60))); + super.setMessageObject(messageObject); } updateButtonState(dataChanged); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java index 069cb57de..b9ec45600 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java @@ -434,10 +434,10 @@ public class ContextLinkCell extends View implements MediaController.FileDownloa fileName = FileLoader.getAttachFileName(result.document); cacheFile = FileLoader.getPathToAttach(result.document); } else if (result.content_url != null) { - fileName = Utilities.MD5(result.content_url) + "." + ImageLoader.getHttpUrlExtension(result.content_url); + fileName = Utilities.MD5(result.content_url) + "." + ImageLoader.getHttpUrlExtension(result.content_url, "jpg"); cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); } else if (result.thumb_url != null) { - fileName = Utilities.MD5(result.thumb_url) + "." + ImageLoader.getHttpUrlExtension(result.thumb_url); + fileName = Utilities.MD5(result.thumb_url) + "." + ImageLoader.getHttpUrlExtension(result.thumb_url, "jpg"); cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); } } else if (gif != null) { 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 cf790ade1..53bb5a867 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -358,10 +358,10 @@ public class DialogCell extends BaseCell { } else { TLRPC.User fromUser = null; TLRPC.Chat fromChat = null; - if (message.messageOwner.from_id > 0) { + if (message.isFromUser()) { fromUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); - } else if (message.messageOwner.from_id < 0) { - fromChat = MessagesController.getInstance().getChat(-message.messageOwner.from_id); + } else { + fromChat = MessagesController.getInstance().getChat(message.messageOwner.to_id.channel_id); } if (lastMessageDate != 0) { @@ -859,7 +859,11 @@ public class DialogCell extends BaseCell { if (messageLayout != null) { canvas.save(); canvas.translate(messageLeft, messageTop); - messageLayout.draw(canvas); + try { + messageLayout.draw(canvas); + } catch (Exception e) { + FileLog.e("tmessages", e); + } canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index aa0c9bffe..2a9aba56a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -16,6 +16,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AvatarDrawable; @@ -34,6 +35,8 @@ public class MentionCell extends LinearLayout { setOrientation(HORIZONTAL); + setBackgroundResource(R.drawable.list_selector); + avatarDrawable = new AvatarDrawable(); avatarDrawable.setSmallStyle(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LastSeenRadioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/ui/Cells/LastSeenRadioCell.java rename to TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java index 3e9187b59..e71b5b78c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/LastSeenRadioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java @@ -22,14 +22,14 @@ import org.telegram.messenger.LocaleController; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RadioButton; -public class LastSeenRadioCell extends FrameLayout { +public class RadioCell extends FrameLayout { private TextView textView; private RadioButton radioButton; private static Paint paint; private boolean needDivider; - public LastSeenRadioCell(Context context) { + public RadioCell(Context context) { super(context); if (paint == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java index a5b6cca6b..5f6238ec1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java @@ -207,6 +207,11 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F if (document != null && document.messageOwner.media != null && document.messageOwner.media.document != null) { int idx; String name = FileLoader.getDocumentFileName(document.messageOwner.media.document); + if (name.length() == 0) { + if (document.isMusic()) { + name = document.getMusicAuthor() + " - " + document.getMusicTitle(); + } + } placeholderImabeView.setVisibility(VISIBLE); extTextView.setVisibility(VISIBLE); placeholderImabeView.setImageResource(getThumbForNameOrMime(name, document.messageOwner.media.document.mime_type)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java index a1d260c67..48d272883 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java @@ -390,10 +390,7 @@ public class SharedLinkCell extends FrameLayout { if (webPage != null && Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { delegate.needOpenWebView(webPage); } else { - Uri uri = Uri.parse(links.get(pressedLink)); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName()); - getContext().startActivity(intent); + AndroidUtilities.openUrl(getContext(), links.get(pressedLink)); } } catch (Exception e) { FileLog.e("tmessages", e); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java index 362144781..c703e0353 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java @@ -226,14 +226,21 @@ public class SharedPhotoVideoCell extends FrameLayoutFixed { PhotoVideoView photoVideoView = photoVideoViews[a]; photoVideoView.imageView.getImageReceiver().setParentMessageObject(messageObject); photoVideoView.imageView.getImageReceiver().setVisible(!PhotoViewer.getInstance().isShowingImage(messageObject), false); - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo && messageObject.messageOwner.media.video != null) { + if (messageObject.isVideo()) { photoVideoView.videoInfoContainer.setVisibility(VISIBLE); - int duration = messageObject.messageOwner.media.video.duration; + int duration = 0; + for (int b = 0; b < messageObject.messageOwner.media.document.attributes.size(); b++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(b); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } int minutes = duration / 60; int seconds = duration - minutes * 60; photoVideoView.videoTextView.setText(String.format("%d:%02d", minutes, seconds)); - if (messageObject.messageOwner.media.video.thumb != null) { - TLRPC.FileLocation location = messageObject.messageOwner.media.video.thumb.location; + if (messageObject.messageOwner.media.document.thumb != null) { + TLRPC.FileLocation location = messageObject.messageOwner.media.document.thumb.location; photoVideoView.imageView.setImage(null, null, null, ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.photo_placeholder_in), null, location, "b", null, 0); } else { photoVideoView.imageView.setImageResource(R.drawable.photo_placeholder_in); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java index 5f51556e7..99261561a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java @@ -9,7 +9,11 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.graphics.Canvas; +import android.os.Build; import android.view.Gravity; +import android.view.View; +import android.view.animation.AccelerateInterpolator; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.R; @@ -21,6 +25,12 @@ import org.telegram.ui.Components.LayoutHelper; public class StickerCell extends FrameLayoutFixed { private BackupImageView imageView; + private TLRPC.Document sticker; + private long lastUpdateTime; + private boolean scaled; + private float scale; + private long time = 0; + private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); public StickerCell(Context context) { super(context); @@ -48,6 +58,7 @@ public class StickerCell extends FrameLayoutFixed { if (document != null && document.thumb != null) { imageView.setImage(document.thumb.location, null, "webp", null); } + sticker = document; if (side == -1) { setBackgroundResource(R.drawable.stickers_back_left); setPadding(AndroidUtilities.dp(7), 0, 0, 0); @@ -65,4 +76,46 @@ public class StickerCell extends FrameLayoutFixed { getBackground().setAlpha(230); } } + + public TLRPC.Document getSticker() { + return sticker; + } + + public void setScaled(boolean value) { + scaled = value; + lastUpdateTime = System.currentTimeMillis(); + invalidate(); + } + + public boolean showingBitmap() { + return imageView.getImageReceiver().getBitmap() != null; + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean result = super.drawChild(canvas, child, drawingTime); + if (child == imageView && (scaled && scale != 0.8f || !scaled && scale != 1.0f)) { + long newTime = System.currentTimeMillis(); + long dt = (newTime - lastUpdateTime); + lastUpdateTime = newTime; + if (scaled && scale != 0.8f) { + scale -= dt / 400.0f; + if (scale < 0.8f) { + scale = 0.8f; + } + } else { + scale += dt / 400.0f; + if (scale > 1.0f) { + scale = 1.0f; + } + } + if (Build.VERSION.SDK_INT >= 11) { + imageView.setScaleX(scale); + imageView.setScaleY(scale); + } + imageView.invalidate(); + invalidate(); + } + return result; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java index ebbdb4da5..af2825e4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java @@ -36,7 +36,7 @@ public class StickerEmojiCell extends FrameLayout { private boolean scaled; private float scale; private long time = 0; - private AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); + private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); public StickerEmojiCell(Context context) { super(context); @@ -63,7 +63,8 @@ public class StickerEmojiCell extends FrameLayout { if (showEmoji) { boolean set = false; - for (TLRPC.DocumentAttribute attribute : document.attributes) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { if (attribute.alt != null && attribute.alt.length() > 0) { emojiTextView.setText(Emoji.replaceEmoji(attribute.alt, emojiTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java index d6103bed9..13b2b705b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -252,7 +252,7 @@ public class ChannelCreateActivity extends BaseFragment implements NotificationC progressDialog.show(); return; } - final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), new ArrayList(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL); + final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), new ArrayList(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, ChannelCreateActivity.this); progressDialog = new ProgressDialog(getParentActivity()); progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); progressDialog.setCanceledOnTouchOutside(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java index 91088c2f1..32afbcb16 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java @@ -47,6 +47,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AvatarDrawable; @@ -81,6 +82,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A private TLRPC.InputFile uploadedAvatar; private boolean wasPrivate; private boolean privateAlertShown; + private boolean signMessages; private boolean createAfterUpload; private boolean donePressed; @@ -133,6 +135,7 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A avatarUpdater.parentFragment = this; avatarUpdater.delegate = this; allowComments = !currentChat.broadcast; + signMessages = currentChat.signatures; return super.onFragmentCreate(); } @@ -229,6 +232,10 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A MessagesController.getInstance().updateChannelUserName(chatId, userNameTextView.getText().toString()); } } + if (signMessages != currentChat.signatures) { + currentChat.signatures = true; + MessagesController.getInstance().toogleChannelSignatures(chatId, signMessages); + } if (uploadedAvatar != null) { MessagesController.getInstance().changeChatAvatar(chatId, uploadedAvatar); } else if (avatar == null && currentChat.photo instanceof TLRPC.TL_chatPhoto) { @@ -392,13 +399,14 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); if (currentChat.megagroup) { infoCell.setText(LocaleController.getString("DescriptionInfoMega", R.string.DescriptionInfoMega)); + infoCell.setBackgroundResource(currentChat.creator ? R.drawable.greydivider : R.drawable.greydivider_bottom); } else { infoCell.setText(LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo)); + infoCell.setBackgroundResource(R.drawable.greydivider); } - infoCell.setBackgroundResource(R.drawable.greydivider); linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - if (!currentChat.megagroup) { + if (/*BuildVars.DEBUG_VERSION && currentChat.megagroup && currentChat.creator || */!currentChat.megagroup) { linearLayout2 = new LinearLayout(context); linearLayout2.setOrientation(LinearLayout.VERTICAL); linearLayout2.setBackgroundColor(0xffffffff); @@ -443,7 +451,11 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A if (wasPrivate && hasFocus && !privateAlertShown) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ChannelWasPrivateAlert", R.string.ChannelWasPrivateAlert)); + if (currentChat.megagroup) { + //builder.setMessage(LocaleController.getString("MegaWasPrivateAlert", R.string.MegaWasPrivateAlert)); + } else { + builder.setMessage(LocaleController.getString("ChannelWasPrivateAlert", R.string.ChannelWasPrivateAlert)); + } builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null); showDialog(builder.create()); } @@ -476,11 +488,14 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A infoCell = new TextInfoPrivacyCell(context); infoCell.setBackgroundResource(R.drawable.greydivider); - infoCell.setText(LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + if (currentChat.megagroup) { + //infoCell.setText(LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp)); + } else { + infoCell.setText(LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + } linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } - /*frameLayout = new FrameLayoutFixed(context); frameLayout.setBackgroundColor(0xffffffff); linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); @@ -502,55 +517,80 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A infoCell.setBackgroundResource(R.drawable.greydivider); linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));*/ - frameLayout = new FrameLayoutFixed(context); - frameLayout.setBackgroundColor(0xffffffff); - linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (!currentChat.megagroup && currentChat.creator) { + frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - TextSettingsCell textCell = new TextSettingsCell(context); - textCell.setTextColor(0xffed3d39); - textCell.setBackgroundResource(R.drawable.list_selector); - if (currentChat.megagroup) { - textCell.setText(LocaleController.getString("DeleteMega", R.string.DeleteMega), false); - } else { - textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false); - } - frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - textCell.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - if (currentChat.megagroup) { - builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); - } else { - builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); + TextCheckCell textCell = new TextCheckCell(context); + textCell.setBackgroundResource(R.drawable.list_selector); + textCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false); + frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + textCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + signMessages = !signMessages; + ((TextCheckCell) v).setChecked(signMessages); } - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); - if (AndroidUtilities.isTablet()) { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats, -(long) chatId); - } else { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - } - MessagesController.getInstance().deleteUserFromChat(chatId, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), info); - finishFragment(); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } - }); + }); - infoCell = new TextInfoPrivacyCell(context); - infoCell.setBackgroundResource(R.drawable.greydivider_bottom); - if (currentChat.megagroup) { - infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo)); - } else { - infoCell.setText(LocaleController.getString("ChannelDeleteInfo", R.string.ChannelDeleteInfo)); + infoCell = new TextInfoPrivacyCell(context); + infoCell.setBackgroundResource(R.drawable.greydivider); + infoCell.setText(LocaleController.getString("ChannelSignMessagesInfo", R.string.ChannelSignMessagesInfo)); + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + if (currentChat.creator) { + frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextSettingsCell textCell = new TextSettingsCell(context); + textCell.setTextColor(0xffed3d39); + textCell.setBackgroundResource(R.drawable.list_selector); + if (currentChat.megagroup) { + textCell.setText(LocaleController.getString("DeleteMega", R.string.DeleteMega), false); + } else { + textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false); + } + frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + textCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + if (currentChat.megagroup) { + builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); + } else { + builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); + } + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats, -(long) chatId); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + } + MessagesController.getInstance().deleteUserFromChat(chatId, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), info); + finishFragment(); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + }); + + infoCell = new TextInfoPrivacyCell(context); + infoCell.setBackgroundResource(R.drawable.greydivider_bottom); + if (currentChat.megagroup) { + infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo)); + } else { + infoCell.setText(LocaleController.getString("ChannelDeleteInfo", R.string.ChannelDeleteInfo)); + } + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); } - linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); nameTextView.setText(currentChat.title); nameTextView.setSelection(nameTextView.length()); @@ -655,11 +695,20 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A for (int a = 0; a < name.length(); a++) { char ch = name.charAt(a); if (a == 0 && ch >= '0' && ch <= '9') { - if (alert) { - showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + if (currentChat.megagroup) { + if (alert) { + //showErrorAlert(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega)); + } else { + //checkTextView.setText(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega)); + checkTextView.setTextColor(0xffcf3030); + } } else { - checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); - checkTextView.setTextColor(0xffcf3030); + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + checkTextView.setTextColor(0xffcf3030); + } } return false; } @@ -675,11 +724,20 @@ public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.A } } if (name == null || name.length() < 5) { - if (alert) { - showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + if (currentChat.megagroup) { + if (alert) { + //showErrorAlert(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega)); + } else { + //checkTextView.setText(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega)); + checkTextView.setTextColor(0xffcf3030); + } } else { - checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); - checkTextView.setTextColor(0xffcf3030); + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + checkTextView.setTextColor(0xffcf3030); + } } return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java index 1e00a6ec2..736be7769 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java @@ -36,7 +36,10 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.RadioCell; import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Cells.UserCell; @@ -78,7 +81,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe if (type == 0) { participantsStartRow = 0; } else if (type == 1) { - participantsStartRow = isAdmin ? 2 : 0; + participantsStartRow = isAdmin && isMegagroup ? 4 : 0; } else if (type == 2) { participantsStartRow = isAdmin ? (isPublic ? 2 : 3) : 0; } @@ -134,7 +137,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - ListView listView = new ListView(context); + final ListView listView = new ListView(context); listView.setEmptyView(emptyView); listView.setDivider(null); listView.setDividerHeight(0); @@ -173,7 +176,33 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } else if (type == 1) { if (isAdmin) { - if (i == 0) { + if (isMegagroup && (i == 1 || i == 2)) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + if (chat == null) { + return; + } + boolean changed = false; + if (i == 1 && !chat.democracy) { + chat.democracy = true; + changed = true; + } else if (i == 2 && chat.democracy) { + chat.democracy = false; + changed = true; + } + if (changed) { + MessagesController.getInstance().toogleChannelInvites(chatId, chat.democracy); + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof RadioCell) { + int num = (Integer) child.getTag(); + ((RadioCell) child).setChecked(num == 0 && chat.democracy || num == 1 && !chat.democracy, true); + } + } + } + return; + } + if (i == participantsStartRow + participants.size()) { Bundle args = new Bundle(); args.putBoolean("onlyUsers", true); args.putBoolean("destroyAfterSelect", true); @@ -192,6 +221,7 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } }); presentFragment(fragment); + return; } } } @@ -243,16 +273,18 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { - final TLRPC.Updates updates = (TLRPC.Updates) response; - MessagesController.getInstance().processUpdates(updates, false); - if (!updates.chats.isEmpty()) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - TLRPC.Chat chat = updates.chats.get(0); - MessagesController.getInstance().loadFullChat(chat.id, 0, true); - } - }, 1000); + if (response != null) { + final TLRPC.Updates updates = (TLRPC.Updates) response; + MessagesController.getInstance().processUpdates(updates, false); + if (!updates.chats.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Chat chat = updates.chats.get(0); + MessagesController.getInstance().loadFullChat(chat.id, 0, true); + } + }, 1000); + } } } }); @@ -487,12 +519,12 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe } } } else if (type == 1) { - if (isAdmin) { - if (i == 0) { - return true; - } else if (i == 1) { - return false; - } + if (i == participantsStartRow + participants.size()) { + return isAdmin; + } else if (i == participantsStartRow + participants.size() + 1) { + return false; + } else if (isMegagroup && isAdmin && i < 4) { + return i == 1 || i == 2; } } return i != participants.size() + participantsStartRow && participants.get(i - participantsStartRow).user_id != UserConfig.getClientUserId(); @@ -502,6 +534,8 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe public int getCount() { if (participants.isEmpty() && type == 0 || loadingUsers && !firstLoaded) { return 0; + } else if (type == 1) { + return participants.size() + (isAdmin ? 2 : 1) + (isAdmin && isMegagroup ? 4 : 0); } return participants.size() + participantsStartRow + 1; } @@ -557,13 +591,14 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe ((TextInfoPrivacyCell) view).setText(String.format("%1$s\n\n%2$s", LocaleController.getString("NoBlockedGroup", R.string.NoBlockedGroup), LocaleController.getString("UnblockText", R.string.UnblockText))); view.setBackgroundResource(R.drawable.greydivider_bottom); } else if (type == 1) { - if (i == 1 && isAdmin) { + if (isAdmin) { if (isMegagroup) { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("MegaAdminsInfo", R.string.MegaAdminsInfo)); + view.setBackgroundResource(R.drawable.greydivider_bottom); } else { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelAdminsInfo", R.string.ChannelAdminsInfo)); + view.setBackgroundResource(R.drawable.greydivider_bottom); } - view.setBackgroundResource(R.drawable.greydivider); } else { ((TextInfoPrivacyCell) view).setText(""); view.setBackgroundResource(R.drawable.greydivider_bottom); @@ -594,12 +629,38 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe actionCell.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink), false); } } else if (type == 1) { - actionCell.setText(LocaleController.getString("ChannelAddAdmin", R.string.ChannelAddAdmin), true); + actionCell.setTextAndIcon(LocaleController.getString("ChannelAddAdmin", R.string.ChannelAddAdmin), R.drawable.managers, false); } } else if (viewType == 3) { if (view == null) { view = new ShadowSectionCell(mContext); } + } else if (viewType == 4) { + if (view == null) { + view = new TextCell(mContext); + view.setBackgroundColor(0xffffffff); + } + ((TextCell) view).setTextAndIcon(LocaleController.getString("ChannelAddAdmin", R.string.ChannelAddAdmin), R.drawable.managers); + } else if (viewType == 5) { + if (view == null) { + view = new HeaderCell(mContext); + view.setBackgroundColor(0xffffffff); + } + ((HeaderCell) view).setText(LocaleController.getString("WhoCanAddMembers", R.string.WhoCanAddMembers)); + } else if (viewType == 6) { + if (view == null) { + view = new RadioCell(mContext); + view.setBackgroundColor(0xffffffff); + } + RadioCell radioCell = (RadioCell) view; + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + if (i == 1) { + radioCell.setTag(0); + radioCell.setText(LocaleController.getString("WhoCanAddMembersAllMembers", R.string.WhoCanAddMembersAllMembers), chat != null && chat.democracy, true); + } else if (i == 2) { + radioCell.setTag(1); + radioCell.setText(LocaleController.getString("WhoCanAddMembersAdmins", R.string.WhoCanAddMembersAdmins), chat != null && !chat.democracy, false); + } } return view; } @@ -608,9 +669,18 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe public int getItemViewType(int i) { if (type == 1) { if (isAdmin) { - if (i == 0) { - return 2; - } else if (i == 1) { + if (isMegagroup) { + if (i == 0) { + return 5; + } else if (i == 1 || i == 2) { + return 6; + } else if (i == 3) { + return 3; + } + } + if (i == participantsStartRow + participants.size()) { + return 4; + } else if (i == participantsStartRow + participants.size() + 1) { return 1; } } @@ -639,12 +709,12 @@ public class ChannelUsersActivity extends BaseFragment implements NotificationCe @Override public int getViewTypeCount() { - return 4; + return 7; } @Override public boolean isEmpty() { - return participants.isEmpty(); + return getCount() == 0 || participants.isEmpty() && loadingUsers; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index d94a3b623..9cd8bbc00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -12,6 +12,7 @@ import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; +import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -26,11 +27,11 @@ import android.media.ExifInterface; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.provider.Browser; import android.provider.ContactsContract; import android.provider.MediaStore; import android.text.TextUtils; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.util.Base64; import android.util.SparseArray; import android.util.SparseIntArray; @@ -182,7 +183,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private TextView bottomOverlayText; private TextView secretViewStatusTextView; private NumberTextView selectedMessagesCountTextView; + private TextView actionModeTextView; private RecyclerListView stickersListView; + private RecyclerListView.OnItemClickListener stickersOnItemClickListener; private StickersAdapter stickersAdapter; private FrameLayout stickersPanel; private TextView muteItem; @@ -315,6 +318,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int share_contact = 17; private final static int mute = 18; private final static int reply = 19; + private final static int edit_done = 20; private final static int bot_help = 30; private final static int bot_settings = 31; @@ -525,7 +529,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } loading = true; - + MessagesController.getInstance().setLastCreatedDialogId(dialog_id, true); if (startLoadFromMessageId != 0) { needSelectFromMessageId = true; waitingForLoad.add(lastLoadIndex); @@ -598,6 +602,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.onDestroy(); } + MessagesController.getInstance().setLastCreatedDialogId(dialog_id, false); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); @@ -651,10 +656,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAttachView.onDestroy(); } AndroidUtilities.unlockOrientation(getParentActivity()); - MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + /*MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); if (messageObject != null && !messageObject.isMusic()) { MediaController.getInstance().stopAudio(); - } + }*/ if (ChatObject.isChannel(currentChat)) { MessagesController.getInstance().startShortPoll(currentChat.id, true); } @@ -698,6 +703,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCanCopyIds[a].clear(); } cantDeleteMessagesCount = 0; + chatActivityEnterView.setEditinigMessageObject(null, false); actionBar.hideActionMode(); updateVisibleRows(); } else { @@ -746,6 +752,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cantDeleteMessagesCount = 0; actionBar.hideActionMode(); updateVisibleRows(); + } else if (id == edit_done) { + if (chatActivityEnterView != null && (chatActivityEnterView.isEditingCaption() || chatActivityEnterView.hasText())) { + chatActivityEnterView.doneEditingMessage(); + actionBar.hideActionMode(); + } } else if (id == delete) { if (getParentActivity() == null) { return; @@ -867,7 +878,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); } - if (messageObject != null && messageObject.messageOwner.id > 0) { + if (messageObject != null && (messageObject.messageOwner.id > 0 || messageObject.messageOwner.id < 0 && currentEncryptedChat != null)) { showReplyPanel(true, messageObject, null, null, false, true); } cantDeleteMessagesCount = 0; @@ -1193,6 +1204,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); + actionModeTextView = new TextView(actionMode.getContext()); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + actionModeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + actionModeTextView.setTextColor(0xff737373); + actionModeTextView.setVisibility(View.GONE); + actionModeTextView.setGravity(Gravity.CENTER_VERTICAL); + actionModeTextView.setText(LocaleController.getString("Edit", R.string.Edit)); + actionMode.addView(actionModeTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); + actionModeTextView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + if (currentEncryptedChat == null) { if (!isBroadcast) { actionModeViews.add(actionMode.addItem(reply, R.drawable.ic_ab_reply, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); @@ -1200,7 +1226,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); actionModeViews.add(actionMode.addItem(forward, R.drawable.ic_ab_fwd_forward, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(edit_done, R.drawable.check_blue, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionMode.getItem(edit_done).setVisibility(View.GONE); } else { + actionModeViews.add(actionMode.addItem(reply, R.drawable.ic_ab_reply, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); } @@ -1541,6 +1570,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setOnInterceptTouchListener(new RecyclerListView.OnInterceptTouchListener() { @Override public boolean onInterceptTouchEvent(MotionEvent event) { + if (chatActivityEnterView != null && chatActivityEnterView.isEditingMessage()) { + return true; + } if (actionBar.isActionModeShowed()) { return false; } @@ -1671,9 +1703,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } TLRPC.TL_messages_reportSpam req = new TLRPC.TL_messages_reportSpam(); - req.peer = new TLRPC.TL_inputPeerUser(); - req.peer.user_id = reportSpamUser.id; - req.peer.access_hash = reportSpamUser.access_hash; + if (currentChat != null) { + req.peer = MessagesController.getInputPeer(-currentChat.id); + } else if (currentUser != null) { + req.peer = MessagesController.getInputPeer(currentUser.id); + } MessagesController.getInstance().blockUser(reportSpamUser.id); ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override @@ -1710,7 +1744,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - if (currentEncryptedChat == null && !isBroadcast) { + if (!isBroadcast) { mentionListView = new RecyclerListView(context); mentionLayoutManager = new LinearLayoutManager(context) { @Override @@ -1770,6 +1804,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionLayoutManager.scrollToPositionWithOffset(0, 10000); } if (allowStickersPanel && (!mentionsAdapter.isBotContext() || (allowContextBotPanel || allowContextBotPanelSecond))) { + if (currentEncryptedChat != null && mentionsAdapter.isBotContext()) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (!preferences.getBoolean("secretbot", false)) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("SecretChatContextBotAlert", R.string.SecretChatContextBotAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + preferences.edit().putBoolean("secretbot", true).commit(); + } + } mentionListView.setVisibility(View.VISIBLE); mentionListView.setTag(null); mentionListAnimation = new AnimatorSetProxy(); @@ -1846,21 +1891,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setUseFullWidth(true); showDialog(builder.create()); } else { - try { - Uri uri = Uri.parse(result.content_url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getParentActivity().getPackageName()); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + AndroidUtilities.openUrl(getParentActivity(), result.content_url); } } })); - mentionsAdapter.setBotInfo(botInfo); + if (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup) { + mentionsAdapter.setBotInfo(botInfo); + } mentionsAdapter.setChatInfo(info); mentionsAdapter.setNeedUsernames(currentChat != null); - mentionsAdapter.setNeedBotContext(currentEncryptedChat == null); + mentionsAdapter.setNeedBotContext(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); mentionsAdapter.setBotsCount(currentChat != null ? botsCount : 1); mentionListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override @@ -1890,6 +1930,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not params.put("id", result.id); params.put("query_id", "" + result.query_id); params.put("bot", "" + mentionsAdapter.getContextBotId()); + params.put("bot_name", mentionsAdapter.getContextBotName()); mentionsAdapter.addRecentBot(); SendMessagesHelper.prepareSendingBotContextResult(result, params, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); chatActivityEnterView.setFieldText(""); @@ -1906,18 +1947,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } Object object = mentionsAdapter.getItem(position); if (object instanceof String) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); - builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - mentionsAdapter.clearRecentHashtags(); + if (mentionsAdapter.isBotCommands()) { + if (URLSpanBotCommand.enabled) { + chatActivityEnterView.setFieldText(""); + chatActivityEnterView.setCommand(null, (String) object, true, currentChat != null && currentChat.megagroup); + return true; } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - return true; + return false; + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + mentionsAdapter.clearRecentHashtags(); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + return true; + } } return false; } @@ -1926,9 +1976,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionListView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int firstVisibleItem = mentionLayoutManager.findFirstVisibleItemPosition(); - int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : firstVisibleItem; - if (visibleItemCount > 0 && firstVisibleItem > mentionsAdapter.getItemCount() - 5) { + int lastVisibleItem = mentionLayoutManager.findLastVisibleItemPosition(); + int visibleItemCount = lastVisibleItem == RecyclerView.NO_POSITION ? 0 : lastVisibleItem; + if (visibleItemCount > 0 && lastVisibleItem > mentionsAdapter.getItemCount() - 5) { mentionsAdapter.searchForContextBotForNextOffset(); } } @@ -1955,6 +2005,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.addToAttachLayout(menuItem); chatActivityEnterView.setId(id_chat_compose_panel); chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands); + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); contentView.addView(chatActivityEnterView, contentView.getChildCount() - 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); chatActivityEnterView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { @Override @@ -1968,7 +2019,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onTextChanged(final CharSequence text, boolean bigChange) { - if (stickersAdapter != null) { + MediaController.getInstance().setInputFieldHasText(text != null && text.length() != 0 || chatActivityEnterView.isEditingMessage()); + if (stickersAdapter != null && !chatActivityEnterView.isEditingMessage()) { stickersAdapter.loadStikersForEmoji(text); } if (mentionsAdapter != null) { @@ -1978,7 +2030,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.cancelRunOnUIThread(waitingForCharaterEnterRunnable); waitingForCharaterEnterRunnable = null; } - if (chatActivityEnterView.isMessageWebPageSearchEnabled()) { + if (chatActivityEnterView.isMessageWebPageSearchEnabled() && (!chatActivityEnterView.isEditingMessage() || !chatActivityEnterView.isEditingCaption())) { if (bigChange) { searchLinks(text, true); } else { @@ -2027,6 +2079,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void onMessageEditEnd() { + mentionsAdapter.setNeedBotContext(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setClickable(true); + chatListView.setLongClickable(true); + actionModeTextView.setVisibility(View.GONE); + selectedMessagesCountTextView.setVisibility(View.VISIBLE); + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + } + @Override public void onWindowSizeChanged(int size) { if (size < AndroidUtilities.dp(72) + ActionBar.getCurrentActionBarHeight()) { @@ -2116,7 +2180,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersPanel.setVisibility(View.GONE); contentView.addView(stickersPanel, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 81.5f, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 38)); - stickersListView = new RecyclerListView(context); + stickersListView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, stickersListView, 0); + return super.onInterceptTouchEvent(event) || result; + } + }; + stickersListView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return StickerPreviewViewer.getInstance().onTouch(event, stickersListView, 0, stickersOnItemClickListener); + } + }); stickersListView.setDisallowInterceptTouchEvents(true); LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); @@ -2126,64 +2202,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersListView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); } stickersPanel.addView(stickersListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78)); - if (currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23) { - chatActivityEnterView.setAllowStickersAndGifs(true, currentEncryptedChat == null); - if (stickersAdapter != null) { - stickersAdapter.onDestroy(); - } - stickersListView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); - stickersListView.setAdapter(stickersAdapter = new StickersAdapter(context, new StickersAdapter.StickersAdapterDelegate() { - @Override - public void needChangePanelVisibility(final boolean show) { - if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { - return; - } - if (show) { - stickersListView.scrollToPosition(0); - stickersPanel.clearAnimation(); - stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); - } - if (runningAnimation != null) { - runningAnimation.cancel(); - runningAnimation = null; - } - if (stickersPanel.getVisibility() != View.INVISIBLE) { - runningAnimation = new AnimatorSetProxy(); - runningAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) - ); - runningAnimation.setDuration(150); - runningAnimation.addListener(new AnimatorListenerAdapterProxy() { - @Override - public void onAnimationEnd(Object animation) { - if (runningAnimation != null && runningAnimation.equals(animation)) { - if (!show) { - stickersAdapter.clearStickers(); - stickersPanel.clearAnimation(); - stickersPanel.setVisibility(View.GONE); - } - runningAnimation = null; - } - } - }); - runningAnimation.start(); - } else if (!show) { - stickersPanel.setVisibility(View.GONE); - } - } - })); - stickersListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - TLRPC.Document document = stickersAdapter.getItem(position); - if (document instanceof TLRPC.TL_document) { - SendMessagesHelper.getInstance().sendSticker(document, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); - showReplyPanel(false, null, null, null, false, true); - } - chatActivityEnterView.setFieldText(""); - } - }); - } + initStickers(); imageView = new ImageView(context); imageView.setImageResource(R.drawable.stickers_back_arrow); @@ -2296,6 +2315,92 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return fragmentView; } + public long getDialogId() { + return dialog_id; + } + + public boolean playFirstUnreadVoiceMessage() { + for (int a = messages.size() - 1; a >= 0; a--) { + MessageObject messageObject = messages.get(a); + if (messageObject.isVoice() && messageObject.isContentUnread() && !messageObject.isOut() && messageObject.messageOwner.to_id.channel_id == 0) { + MediaController.getInstance().setVoiceMessagesPlaylist(MediaController.getInstance().playAudio(messageObject) ? createVoiceMessagesPlaylist(messageObject, true) : null, true); + return true; + } + } + if (Build.VERSION.SDK_INT >= 23 && getParentActivity() != null) { + if (getParentActivity().checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3); + return true; + } + } + return false; + } + + private void initStickers() { + if (chatActivityEnterView == null || getParentActivity() == null || stickersAdapter != null || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 23) { + return; + } + if (stickersAdapter != null) { + stickersAdapter.onDestroy(); + } + stickersListView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + stickersListView.setAdapter(stickersAdapter = new StickersAdapter(getParentActivity(), new StickersAdapter.StickersAdapterDelegate() { + @Override + public void needChangePanelVisibility(final boolean show) { + if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { + return; + } + if (show) { + stickersListView.scrollToPosition(0); + stickersPanel.clearAnimation(); + stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); + } + if (runningAnimation != null) { + runningAnimation.cancel(); + runningAnimation = null; + } + if (stickersPanel.getVisibility() != View.INVISIBLE) { + runningAnimation = new AnimatorSetProxy(); + runningAnimation.playTogether( + ObjectAnimatorProxy.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) + ); + runningAnimation.setDuration(150); + runningAnimation.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + if (!show) { + stickersAdapter.clearStickers(); + stickersPanel.clearAnimation(); + stickersPanel.setVisibility(View.GONE); + if (StickerPreviewViewer.getInstance().isVisible()) { + StickerPreviewViewer.getInstance().close(); + } + StickerPreviewViewer.getInstance().reset(); + } + runningAnimation = null; + } + } + }); + runningAnimation.start(); + } else if (!show) { + stickersPanel.setVisibility(View.GONE); + } + } + })); + stickersListView.setOnItemClickListener(stickersOnItemClickListener = new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + TLRPC.Document document = stickersAdapter.getItem(position); + if (document instanceof TLRPC.TL_document) { + SendMessagesHelper.getInstance().sendSticker(document, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); + showReplyPanel(false, null, null, null, false, true); + } + chatActivityEnterView.setFieldText(""); + } + }); + } + private void showGifHint() { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (preferences.getBoolean("gifhint", false)) { @@ -2506,7 +2611,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); return; } - PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(false, currentEncryptedChat == null, ChatActivity.this); + PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(false, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46, ChatActivity.this); fragment.setDelegate(new PhotoAlbumPickerActivity.PhotoAlbumPickerActivityDelegate() { @Override public void didSelectPhotos(ArrayList photos, ArrayList captions, ArrayList webPhotos) { @@ -2640,19 +2745,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return !(dialog == chatAttachViewSheet && PhotoViewer.getInstance().isVisible()) && super.dismissDialogOnPause(dialog); } - private void searchLinks(final CharSequence charSequence, boolean force) { - if (currentEncryptedChat != null) { + private void searchLinks(final CharSequence charSequence, final boolean force) { + if (currentEncryptedChat != null && (MessagesController.getInstance().secretWebpagePreview == 0 || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46)) { return; } if (force && foundWebPage != null) { if (foundWebPage.url != null) { int index = TextUtils.indexOf(charSequence, foundWebPage.url); - char lastChar; - boolean lenEqual; + char lastChar = 0; + boolean lenEqual = false; if (index == -1) { - index = TextUtils.indexOf(charSequence, foundWebPage.display_url); - lenEqual = index != -1 && index + foundWebPage.display_url.length() == charSequence.length(); - lastChar = index != -1 && !lenEqual ? charSequence.charAt(index + foundWebPage.display_url.length()) : 0; + if (foundWebPage.display_url != null) { + index = TextUtils.indexOf(charSequence, foundWebPage.display_url); + lenEqual = index != -1 && index + foundWebPage.display_url.length() == charSequence.length(); + lastChar = index != -1 && !lenEqual ? charSequence.charAt(index + foundWebPage.display_url.length()) : 0; + } } else { lenEqual = index + foundWebPage.url.length() == charSequence.length(); lastChar = !lenEqual ? charSequence.charAt(index + foundWebPage.url.length()) : 0; @@ -2676,6 +2783,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not try { Matcher m = AndroidUtilities.WEB_URL.matcher(charSequence); while (m.find()) { + if (m.start() > 0) { + if (charSequence.charAt(m.start() - 1) == '@') { + continue; + } + } if (urls == null) { urls = new ArrayList<>(); } @@ -2724,6 +2836,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textToCheck = charSequence; } + if (currentEncryptedChat != null && MessagesController.getInstance().secretWebpagePreview == 2) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + MessagesController.getInstance().secretWebpagePreview = 1; + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + foundUrls = null; + searchLinks(charSequence, force); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setMessage(LocaleController.getString("SecretLinkPreviewAlert", R.string.SecretLinkPreviewAlert)); + showDialog(builder.create()); + + MessagesController.getInstance().secretWebpagePreview = 0; + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + } + }); + return; + } + final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); if (textToCheck instanceof String) { req.message = (String) textToCheck; @@ -2744,6 +2882,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (foundWebPage instanceof TLRPC.TL_webPagePending) { pendingLinkSearchString = req.message; } + if (currentEncryptedChat != null && foundWebPage instanceof TLRPC.TL_webPagePending) { + foundWebPage.url = req.message; + } showReplyPanel(true, null, null, foundWebPage, false, true); } else { if (foundWebPage != null) { @@ -2797,14 +2938,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (messageObject != null) { String name; - if (messageObject.messageOwner.from_id > 0) { + if (messageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); if (user == null) { return; } name = UserObject.getUserName(user); } else { - TLRPC.Chat chat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageObject.messageOwner.to_id.channel_id); if (chat == null) { return; } @@ -2841,10 +2982,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setForceShowSendButton(true, animated); ArrayList uids = new ArrayList<>(); replyIconImageView.setImageResource(R.drawable.forward_blue); - uids.add(messageObjects.get(0).messageOwner.from_id); + MessageObject object = messageObjects.get(0); + if (object.isFromUser()) { + uids.add(object.messageOwner.from_id); + } else { + uids.add(-object.messageOwner.to_id.channel_id); + } int type = messageObjects.get(0).type; for (int a = 1; a < messageObjects.size(); a++) { - Integer uid = messageObjects.get(a).messageOwner.from_id; + object = messageObjects.get(a); + Integer uid; + if (object.isFromUser()) { + uid = object.messageOwner.from_id; + } else { + uid = -object.messageOwner.to_id.channel_id; + } if (!uids.contains(uid)) { uids.add(uid); } @@ -2919,8 +3071,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (type == 12) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedContact", messageObjects.size())); - } else if (type == 2 || type == 14) { + } else if (type == 2) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedAudio", messageObjects.size())); + } else if (type == 14) { + replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedMusic", messageObjects.size())); } else if (type == 13) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedSticker", messageObjects.size())); } else if (type == 8 || type == 9) { @@ -2967,7 +3121,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) replyNameTextView.getLayoutParams(); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) replyObjectTextView.getLayoutParams(); TLRPC.PhotoSize photoSize = messageObject != null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80) : null; - if (photoSize == null || messageObject.type == 13) { + if (photoSize == null || messageObject.type == 13 || messageObject != null && messageObject.isSecretMedia()) { replyImageView.setImageBitmap(null); replyImageLocation = null; replyImageView.setVisibility(View.INVISIBLE); @@ -3171,6 +3325,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (query) { + if (currentEncryptedChat != null && !MessagesStorage.getInstance().checkMessageId(dialog_id, startLoadFromMessageId)) { + return; + } clearChatData(); loadsCount = 0; unread_to_load = 0; @@ -3261,6 +3418,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { bottomOverlay.setVisibility(View.INVISIBLE); } + checkRaiseSensors(); if (hideKeyboard) { chatActivityEnterView.hidePopup(false); if (getParentActivity() != null) { @@ -3345,15 +3503,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 1; } else { if (!messageObject.isMediaEmpty()) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - if (messageObject.isSticker()) { - TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); - if (inputStickerSet != null && !StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + if (messageObject.isVoice()) { + return 2; + } else if (messageObject.isSticker()) { + TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + return 7; + } + } else if (inputStickerSet instanceof TLRPC.TL_inputStickerSetShortName) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.short_name)) { return 7; } } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { boolean canSave = false; if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() != 0) { File f = new File(messageObject.messageOwner.attachPath); @@ -3407,15 +3570,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else { if (!messageObject.isMediaEmpty()) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - if (messageObject.isSticker()) { - TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); - if (inputStickerSet != null && !StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + if (messageObject.isVoice()) { + return 2; + } else if (messageObject.isSticker()) { + TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetShortName) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.short_name)) { return 7; } } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { boolean canSave = false; if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() != 0) { File f = new File(messageObject.messageOwner.attachPath); @@ -3479,7 +3643,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final ActionBarMenuItem replyItem = actionBar.createActionMode().getItem(reply); if (replyItem != null) { boolean allowChatActions = true; - if (isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { allowChatActions = false; } final int newVisibility = allowChatActions && selectedMessagesIds[0].size() + selectedMessagesIds[1].size() == 1 ? View.VISIBLE : View.GONE; @@ -4127,9 +4291,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (load_type == 1) { Collections.reverse(messArr); } - ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + if (currentEncryptedChat == null) { + ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + } for (int a = 0; a < messArr.size(); a++) { MessageObject obj = messArr.get(a); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } if (messagesDict[loadIndex].containsKey(obj.getId())) { continue; } @@ -4491,6 +4660,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerDrawable != null) { TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction; @@ -4529,6 +4701,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messagesDict[0].containsKey(obj.getId())) { continue; } + obj.checkLayout(); currentMaxDate = Math.max(currentMaxDate, obj.messageOwner.date); if (obj.getId() > 0) { currentMinMsgId = Math.max(obj.getId(), currentMinMsgId); @@ -4564,8 +4737,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean unreadUpdated = true; int oldCount = messages.size(); int addedCount = 0; + HashMap> webpagesToReload = null; for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerDrawable != null) { TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction; @@ -4574,6 +4751,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messagesDict[0].containsKey(obj.getId())) { continue; } + if (currentEncryptedChat != null && obj.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && obj.messageOwner.media.webpage instanceof TLRPC.TL_webPageUrlPending) { + if (webpagesToReload == null) { + webpagesToReload = new HashMap<>(); + } + ArrayList arrayList = webpagesToReload.get(obj.messageOwner.media.webpage.url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + webpagesToReload.put(obj.messageOwner.media.webpage.url, arrayList); + } + arrayList.add(obj); + } + obj.checkLayout(); if (obj.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) { final Bundle bundle = new Bundle(); bundle.putInt("chat_id", obj.messageOwner.action.channel_id); @@ -4676,6 +4865,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateChat = true; } } + if (webpagesToReload != null) { + MessagesController.getInstance().reloadWebPages(dialog_id, webpagesToReload); + } if (progressView != null) { progressView.setVisibility(View.INVISIBLE); @@ -4905,7 +5097,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; ArrayList messArr = new ArrayList<>(); messArr.add(obj); - ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + if (currentEncryptedChat == null) { + ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + } if (chatAdapter != null) { chatAdapter.updateRowWithMessageObject(obj); } @@ -4983,7 +5177,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not botsCount = info.bot_info.size(); for (int a = 0; a < info.bot_info.size(); a++) { TLRPC.BotInfo bot = info.bot_info.get(a); - if (!bot.commands.isEmpty()) { + if (!bot.commands.isEmpty() && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { hasBotsCommands = true; } botInfo.put(bot.user_id, bot); @@ -4991,7 +5185,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatListView != null) { chatListView.invalidateViews(); } - if (mentionsAdapter != null) { + if (mentionsAdapter != null && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { mentionsAdapter.setBotInfo(botInfo); } } @@ -5039,6 +5233,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not currentEncryptedChat = chat; updateContactStatus(); updateSecretStatus(); + initStickers(); + if (chatActivityEnterView != null) { + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + } + if (mentionsAdapter != null) { + mentionsAdapter.setNeedBotContext(!chatActivityEnterView.isEditingMessage() && (currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46)); + } } } else if (id == NotificationCenter.messagesReadEncrypted) { int encId = (Integer) args[0]; @@ -5083,7 +5284,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatAudioCell) { ChatAudioCell cell = (ChatAudioCell) view; if (cell.getMessageObject() != null && cell.getMessageObject().getId() == mid) { - cell.updateProgress(); + MessageObject playing = cell.getMessageObject(); + MessageObject player = MediaController.getInstance().getPlayingMessageObject(); + if (player != null) { + playing.audioProgress = player.audioProgress; + playing.audioProgressSec = player.audioProgressSec; + cell.updateProgress(); + } break; } } else if (view instanceof ChatMusicCell) { @@ -5180,7 +5387,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (finalSize != 0 && dialog_id == messageObject.getDialogId()) { MessageObject currentObject = messagesDict[0].get(messageObject.getId()); if (currentObject != null) { - currentObject.messageOwner.media.video.size = (int) finalSize; + currentObject.messageOwner.media.document.size = (int) finalSize; updateVisibleRows(); } } @@ -5239,12 +5446,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean changed = false; boolean mediaUpdated = false; ArrayList messageObjects = (ArrayList) args[1]; - for (MessageObject messageObject : messageObjects) { + for (int a = 0; a < messageObjects.size(); a++) { + MessageObject messageObject = messageObjects.get(a); MessageObject old = messagesDict[loadIndex].get(messageObject.getId()); if (old != null) { if (!mediaUpdated && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { mediaUpdated = true; } + if (old.replyMessageObject != null) { + messageObject.replyMessageObject = old.replyMessageObject; + } messagesDict[loadIndex].put(old.getId(), messageObject); int index = messages.indexOf(old); if (index >= 0) { @@ -5323,14 +5534,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (classGuid == guid) { TLRPC.BotInfo info = (TLRPC.BotInfo) args[0]; if (currentEncryptedChat == null) { - if (!info.commands.isEmpty()) { + if (!info.commands.isEmpty() && !ChatObject.isChannel(currentChat)) { hasBotsCommands = true; } botInfo.put(info.user_id, info); if (chatAdapter != null) { chatAdapter.notifyItemChanged(0); } - if (mentionsAdapter != null) { + if (mentionsAdapter != null && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { mentionsAdapter.setBotInfo(botInfo); } if (chatActivityEnterView != null) { @@ -5509,6 +5720,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } muteItem.setVisibility(View.VISIBLE); } + checkRaiseSensors(); } private void updateSpamView() { @@ -5626,11 +5838,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private void checkRaiseSensors() { + if (!ApplicationLoader.mainInterfacePaused && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && (bottomOverlay == null || bottomOverlay.getVisibility() != View.VISIBLE)) { + MediaController.getInstance().setAllowStartRecord(true); + } else { + MediaController.getInstance().setAllowStartRecord(false); + } + } + @Override public void onResume() { super.onResume(); AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + MediaController.getInstance().startRaiseToEarSensors(this); + checkRaiseSensors(); checkActionBarMenu(); if (replyImageLocation != null && replyImageView != null) { @@ -5742,14 +5964,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } - chatListView.setOnItemLongClickListener(onItemLongClickListener); - chatListView.setOnItemClickListener(onItemClickListener); - chatListView.setLongClickable(true); + if (chatActivityEnterView == null || !chatActivityEnterView.isEditingMessage()) { + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setLongClickable(true); + } } @Override public void onPause() { super.onPause(); + MediaController.getInstance().stopRaiseToEarSensors(this); if (menuItem != null) { menuItem.closeSubMenu(); } @@ -5758,12 +5983,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationsController.getInstance().setOpennedDialogId(0); if (chatActivityEnterView != null) { chatActivityEnterView.onPause(); - String text = chatActivityEnterView.getFieldText(); - if (text != null && !text.equals("@gif ")) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - SharedPreferences.Editor editor = preferences.edit(); - editor.putString("dialog_" + dialog_id, text); - editor.commit(); + if (!chatActivityEnterView.isEditingMessage()) { + String text = chatActivityEnterView.getFieldText(); + if (text != null && !text.equals("@gif ")) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("dialog_" + dialog_id, text); + editor.commit(); + } } chatActivityEnterView.setFieldFocused(false); } @@ -5824,8 +6051,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (!AndroidUtilities.isTablet() && ApplicationLoader.applicationContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { selectedMessagesCountTextView.setTextSize(18); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); } else { selectedMessagesCountTextView.setTextSize(20); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); } int padding = (ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48)) / 2; @@ -5963,7 +6192,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionBar.hideActionMode(); boolean allowChatActions = true; - if (type == 1 && message.getDialogId() == mergeDialogId || message.getId() < 0 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || type == 1 && message.getDialogId() == mergeDialogId || currentEncryptedChat == null && message.getId() < 0 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { allowChatActions = false; } @@ -5989,6 +6218,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(8); } + if (message.canEditMessage(currentChat)) { + items.add(LocaleController.getString("Edit", R.string.Edit)); + options.add(12); + } if (message.canDeleteMessage(currentChat)) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); @@ -6020,7 +6253,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(11); } } else if (type == 4) { - if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (selectedObject.isVideo()) { + items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + options.add(4); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); + } else if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { if (MessageObject.isNewGifDocument(selectedObject.messageOwner.media.document)) { items.add(LocaleController.getString("SaveToGIFs", R.string.SaveToGIFs)); options.add(11); @@ -6028,7 +6266,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(selectedObject.isMusic() ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); options.add(10); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); } else { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(4); @@ -6037,7 +6275,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(LocaleController.getString("ApplyLocalizationFile", R.string.ApplyLocalizationFile)); options.add(5); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); } else if (type == 6) { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(7); @@ -6051,20 +6289,33 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } items.add(LocaleController.getString("Forward", R.string.Forward)); options.add(2); + if (message.canEditMessage(currentChat)) { + items.add(LocaleController.getString("Edit", R.string.Edit)); + options.add(12); + } if (message.canDeleteMessage(currentChat)) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); } } else { + if (allowChatActions) { + items.add(LocaleController.getString("Reply", R.string.Reply)); + options.add(8); + } if (type == 3) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); } else if (type == 4) { - if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (selectedObject.isVideo()) { + items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + options.add(4); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); + } else if (!selectedObject.isVideo() && selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { items.add(selectedObject.isMusic() ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); options.add(10); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); } else { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(4); @@ -6100,6 +6351,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return; } + + final ActionBarMenu actionMode = actionBar.createActionMode(); + View item = actionMode.getItem(forward); + if (item != null) { + item.setVisibility(View.VISIBLE); + } + item = actionMode.getItem(delete); + if (item != null) { + item.setVisibility(View.VISIBLE); + } + item = actionMode.getItem(edit_done); + if (item != null) { + item.setVisibility(View.GONE); + } + actionBar.showActionMode(); if (Build.VERSION.SDK_INT >= 11) { @@ -6130,6 +6396,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (option == 1) { if (getParentActivity() == null) { + selectedObject = null; return; } final MessageObject finalSelectedObject = selectedObject; @@ -6187,14 +6454,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (selectedObject.type == 3 || selectedObject.type == 1) { if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; return; } MediaController.saveFile(path, getParentActivity(), selectedObject.type == 3 ? 1 : 0, null); - } else if (selectedObject.type == 8 || selectedObject.type == 9 || selectedObject.type == 14) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(selectedObject.messageOwner.media.document.mime_type); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); } } else if (option == 5) { File locFile = null; @@ -6215,6 +6478,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(new LanguageSelectActivity()); } else { if (getParentActivity() == null) { + selectedObject = null; return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); @@ -6224,7 +6488,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showDialog(builder.create()); } } - } else if (option == 6 || option == 7) { + } else if (option == 6) { String path = selectedObject.messageOwner.attachPath; if (path != null && path.length() > 0) { File temp = new File(path); @@ -6235,20 +6499,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (path == null || path.length() == 0) { path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); } - if (selectedObject.type == 8 || selectedObject.type == 9 || selectedObject.type == 14) { - if (option == 6) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(selectedObject.messageOwner.media.document.mime_type); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); - } else { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); - return; - } - MediaController.saveFile(path, getParentActivity(), 0, null); + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType(selectedObject.messageOwner.media.document.mime_type); + intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); + getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); + } else if (option == 7) { + String path = selectedObject.messageOwner.attachPath; + if (path != null && path.length() > 0) { + File temp = new File(path); + if (!temp.exists()) { + path = null; } } + if (path == null || path.length() == 0) { + path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); + } + if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; + return; + } + MediaController.saveFile(path, getParentActivity(), 0, null); } else if (option == 8) { showReplyPanel(true, selectedObject, null, null, false, true); } else if (option == 9) { @@ -6256,6 +6527,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (option == 10) { if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; return; } String fileName = FileLoader.getDocumentFileName(selectedObject.messageOwner.media.document); @@ -6301,6 +6573,81 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showGifHint(); chatActivityEnterView.addRecentGif(searchImage); + } else if (option == 12) { + if (getParentActivity() == null) { + selectedObject = null; + return; + } + final MessageObject editingMessageObject = selectedObject; + final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + TLRPC.TL_channels_getMessageEditData req = new TLRPC.TL_channels_getMessageEditData(); + req.channel = MessagesController.getInputChannel(currentChat); + req.id = selectedObject.getId(); + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!getParentActivity().isFinishing()) { + progressDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (response != null) { + TLRPC.TL_channels_messageEditData res = (TLRPC.TL_channels_messageEditData) response; + if (mentionsAdapter != null) { + mentionsAdapter.setNeedBotContext(false); + chatListView.setOnItemLongClickListener(null); + chatListView.setOnItemClickListener(null); + chatListView.setClickable(false); + chatListView.setLongClickable(false); + chatActivityEnterView.setEditinigMessageObject(editingMessageObject, res.caption); + actionModeTextView.setVisibility(View.VISIBLE); + selectedMessagesCountTextView.setVisibility(View.GONE); + + chatActivityEnterView.setAllowStickersAndGifs(false, false); + final ActionBarMenu actionMode = actionBar.createActionMode(); + actionMode.getItem(reply).setVisibility(View.GONE); + actionMode.getItem(copy).setVisibility(View.GONE); + actionMode.getItem(forward).setVisibility(View.GONE); + actionMode.getItem(delete).setVisibility(View.GONE); + actionMode.getItem(edit_done).setVisibility(View.VISIBLE); + actionBar.showActionMode(); + } + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + } + }); + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } } selectedObject = null; } @@ -6371,6 +6718,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); } + chatActivityEnterView.setEditinigMessageObject(null, false); actionBar.hideActionMode(); cantDeleteMessagesCount = 0; updateVisibleRows(); @@ -6442,6 +6790,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private ArrayList createVoiceMessagesPlaylist(MessageObject startMessageObject, boolean playingUnreadMedia) { + ArrayList messageObjects = new ArrayList<>(); + messageObjects.add(startMessageObject); + int messageId = startMessageObject.getId(); + if (messageId != 0) { + boolean started = false; + for (int a = messages.size() - 1; a >= 0; a--) { + MessageObject messageObject = messages.get(a); + if ((currentEncryptedChat == null && messageObject.getId() > messageId || currentEncryptedChat != null && messageObject.getId() < messageId) && messageObject.isVoice() && (!playingUnreadMedia || messageObject.isContentUnread() && !messageObject.isOut())) { + messageObjects.add(messageObject); + } + } + } + return messageObjects; + } + private void alertUserOpenError(MessageObject message) { if (getParentActivity() == null) { return; @@ -6461,9 +6825,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not avatarContainer.setVisibility(View.GONE); headerItem.setVisibility(View.GONE); attachItem.setVisibility(View.GONE); - searchItem.setVisibility(View.VISIBLE); - searchUpItem.setVisibility(View.VISIBLE); - searchDownItem.setVisibility(View.VISIBLE); + if (searchUpItem.getVisibility() != View.VISIBLE) { + searchItem.setVisibility(View.VISIBLE); + searchUpItem.setVisibility(View.VISIBLE); + searchDownItem.setVisibility(View.VISIBLE); + } updateSearchButtons(0); openSearchKeyboard = text == null; searchItem.openSearch(openSearchKeyboard); @@ -6639,6 +7005,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (viewType == 2) { view = new ChatAudioCell(mContext); + ((ChatAudioCell) view).setAudioDelegate(new ChatAudioCell.ChatAudioCellDelegate() { + @Override + public boolean needPlayAudio(MessageObject messageObject) { + boolean result = MediaController.getInstance().playAudio(messageObject); + MediaController.getInstance().setVoiceMessagesPlaylist(result ? createVoiceMessagesPlaylist(messageObject, false) : null, false); + return result; + } + }); } else if (viewType == 3) { view = new ChatContactCell(mContext); } else if (viewType == 4) { @@ -6681,13 +7055,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.closeKeyboard(); } BottomSheet.Builder builder = new BottomSheet.Builder(mContext, true); - builder.setCustomView(new ShareFrameLayout(mContext, builder.create(), cell.getMessageObject())).setApplyTopPaddings(false); + builder.setCustomView(new ShareFrameLayout(mContext, builder.create(), cell.getMessageObject(), ChatObject.isChannel(currentChat) && !currentChat.megagroup && currentChat.username != null && currentChat.username.length() > 0)).setApplyTopPaddings(false); builder.setUseFullWidth(false); showDialog(builder.create()); } @Override - public void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat) { + public void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId) { if (actionBar.isActionModeShowed()) { processRowSelect(cell); return; @@ -6695,6 +7069,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chat != null && chat != currentChat) { Bundle args = new Bundle(); args.putInt("chat_id", chat.id); + if (postId != 0) { + args.putInt("message_id", postId); + } presentFragment(new ChatActivity(args), true); } } @@ -6751,24 +7128,57 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setCommand(messageObject, str, longPress, currentChat != null && currentChat.megagroup); } } - } else if (url instanceof URLSpanReplacement) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("OpenUrlAlert", R.string.OpenUrlAlert, ((URLSpanReplacement) url).getURL())); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - url.onClick(fragmentView); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); } else { - url.onClick(fragmentView); + final String urlFinal = ((URLSpan) url).getURL(); + if (longPress) { + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setTitle(urlFinal); + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + if (which == 0) { + AndroidUtilities.openUrl(getParentActivity(), urlFinal); + } else if (which == 1) { + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(urlFinal); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", urlFinal); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + showDialog(builder.create()); + } else { + if (url instanceof URLSpanReplacement) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("OpenUrlAlert", R.string.OpenUrlAlert, ((URLSpanReplacement) url).getURL())); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + try { + AndroidUtilities.openUrl(getParentActivity(), urlFinal); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (url instanceof URLSpan) { + AndroidUtilities.openUrl(getParentActivity(), urlFinal); + } else { + url.onClick(fragmentView); + } + } } } @@ -6791,9 +7201,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didPressedViaBot(ChatBaseCell cell, TLRPC.User user) { - if (chatActivityEnterView != null && user != null && user.username != null && user.username.length() > 0) { - chatActivityEnterView.setFieldText("@" + user.username + " "); + public void didPressedViaBot(ChatBaseCell cell, String username) { + if (bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE || bottomOverlay != null && bottomOverlay.getVisibility() == View.VISIBLE) { + return; + } + if (chatActivityEnterView != null && username != null && username.length() > 0) { + chatActivityEnterView.setFieldText("@" + username + " "); chatActivityEnterView.openKeyboard(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java index 1e3998cef..c77407c64 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -13,12 +13,9 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; -import android.provider.Browser; -import org.telegram.messenger.FileLog; +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; @@ -97,13 +94,7 @@ public class AlertsCreator { builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("NobodyLikesSpamUrl", R.string.NobodyLikesSpamUrl))); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, fragment.getParentActivity().getPackageName()); - fragment.getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + AndroidUtilities.openUrl(fragment.getParentActivity(), LocaleController.getString("NobodyLikesSpamUrl", R.string.NobodyLikesSpamUrl)); } }); break; @@ -144,6 +135,16 @@ public class AlertsCreator { builder.setMessage(LocaleController.getString("GroupUserCantBot", R.string.GroupUserCantBot)); } break; + case "USER_PRIVACY_RESTRICTED": + if (isChannel) { + builder.setMessage(LocaleController.getString("InviteToChannelError", R.string.InviteToChannelError)); + } else { + builder.setMessage(LocaleController.getString("InviteToGroupError", R.string.InviteToGroupError)); + } + break; + case "USERS_TOO_FEW": + builder.setMessage(LocaleController.getString("CreateGroupError", R.string.CreateGroupError)); + break; } builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); fragment.showDialog(builder.create(), true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 217d44621..7a8bda10b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -21,7 +21,9 @@ import android.media.AudioManager; import android.os.Build; import android.os.PowerManager; import android.text.Editable; +import android.text.InputFilter; import android.text.Layout; +import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; @@ -42,6 +44,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; +import android.widget.Toast; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ChatObject; @@ -50,6 +53,7 @@ import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationsController; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.FileLog; import org.telegram.messenger.NotificationCenter; @@ -66,6 +70,7 @@ import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.ApplicationLoader; import org.telegram.ui.StickersActivity; +import java.io.File; import java.util.Locale; public class ChatActivityEnterView extends FrameLayoutFixed implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate { @@ -78,6 +83,64 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat void onAttachButtonShow(); void onWindowSizeChanged(int size); void onStickersTab(boolean opened); + void onMessageEditEnd(); + } + + private class SeekBarWaveformView extends View { + + private SeekBarWaveform seekBarWaveform; + + public SeekBarWaveformView(Context context) { + super(context); + seekBarWaveform = new SeekBarWaveform(context); + seekBarWaveform.setColors(0xffa2cef8, 0xffffffff, 0xffa2cef8); + seekBarWaveform.setDelegate(new SeekBar.SeekBarDelegate() { + @Override + public void onSeekBarDrag(float progress) { + audioToSendMessageObject.audioProgress = progress; + MediaController.getInstance().seekToProgress(audioToSendMessageObject, progress); + } + }); + } + + public void setWaveform(byte[] waveform) { + seekBarWaveform.setWaveform(waveform); + invalidate(); + } + + public void setProgress(float progress) { + seekBarWaveform.setProgress(progress); + invalidate(); + } + + public boolean isDragging() { + return seekBarWaveform.isDragging(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean result = seekBarWaveform.onTouch(event.getAction(), event.getX(), event.getY()); + if (result) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + requestDisallowInterceptTouchEvent(true); + } + invalidate(); + } + return result || super.onTouchEvent(event); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + seekBarWaveform.width = right - left; + seekBarWaveform.height = bottom - top; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + seekBarWaveform.draw(canvas); + } } private class EditTextCaption extends EditText { @@ -137,16 +200,20 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (captionLayout != null && userNameLength == length()) { - Paint paint = getPaint(); - int oldColor = getPaint().getColor(); - paint.setColor(0xffb2b2b2); - canvas.save(); - canvas.translate(xOffset, yOffset); - captionLayout.draw(canvas); - canvas.restore(); - paint.setColor(oldColor); + try { + super.onDraw(canvas); + if (captionLayout != null && userNameLength == length()) { + Paint paint = getPaint(); + int oldColor = getPaint().getColor(); + paint.setColor(0xffb2b2b2); + canvas.save(); + canvas.translate(xOffset, yOffset); + captionLayout.draw(canvas); + canvas.restore(); + paint.setColor(oldColor); + } + } catch (Exception e) { + FileLog.e("tmessages", e); } } @@ -167,21 +234,33 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private TextView recordTimeText; private ImageView audioSendButton; private FrameLayout recordPanel; + private FrameLayout recordedAudioPanel; + private SeekBarWaveformView recordedAudioSeekBar; + private ImageView recordedAudioPlayButton; + private TextView recordedAudioTimeTextView; private LinearLayout slideText; private RecordDot recordDot; private SizeNotifierFrameLayout sizeNotifierLayout; private LinearLayout attachButton; private ImageView botButton; private LinearLayout textFieldContainer; + private FrameLayout sendButtonContainer; private View topView; private PopupWindow botKeyboardPopup; private BotKeyboardView botKeyboardView; private ImageView asAdminButton; + private ImageView notifyButton; private RecordCircle recordCircle; private ContextProgressView contextProgressView; + private MessageObject editingMessageObject; + private boolean editingCaption; + private int currentPopupContentType = -1; + private boolean silent; + private boolean canWriteToChannel; + private boolean isAsAdmin; private boolean adminModeAvailable; @@ -228,6 +307,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private boolean messageWebPageSearch = true; private ChatActivityEnterViewDelegate delegate; + private TLRPC.TL_document audioToSend; + private String audioToSendPath; + private MessageObject audioToSendMessageObject; + private float topViewAnimation; private boolean topViewShowed; private boolean needShowTopView; @@ -270,16 +353,16 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override protected void onDraw(Canvas canvas) { dotDrawable.setBounds(0, 0, AndroidUtilities.dp(11), AndroidUtilities.dp(11)); - dotDrawable.setAlpha(185 + (int) (70 * alpha)); + dotDrawable.setAlpha((int) (255 * alpha)); long dt = (System.currentTimeMillis() - lastUpdateTime); if (!isIncr) { - alpha -= dt / 200.0f; + alpha -= dt / 400.0f; if (alpha <= 0) { alpha = 0; isIncr = true; } } else { - alpha += dt / 200.0f; + alpha += dt / 400.0f; if (alpha >= 1) { alpha = 1; isIncr = false; @@ -379,6 +462,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidSent); NotificationCenter.getInstance().addObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioRouteChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged); parentActivity = context; parentFragment = fragment; sizeNotifierLayout = parent; @@ -491,7 +576,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (count > 2 || charSequence == null || charSequence.length() == 0) { messageWebPageSearch = true; } - delegate.onTextChanged(charSequence, before > count + 1 || (count - before) > 2); + if (!ignoreTextChange) { + delegate.onTextChanged(charSequence, before > count + 1 || (count - before) > 2); + } } if (innerTextChange != 2 && before != count && (count - before) > 1) { processChange = true; @@ -584,8 +671,88 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat preferences.edit().putBoolean("asadmin_" + dialog_id, isAsAdmin).commit(); } }); + + notifyButton = new ImageView(context); + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + notifyButton.setScaleType(ImageView.ScaleType.CENTER); + notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE); + attachButton.addView(notifyButton, LayoutHelper.createLinear(48, 48)); + notifyButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + silent = !silent; + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).edit().putBoolean("silent_" + dialog_id, silent).commit(); + NotificationsController.updateServerNotificationsSettings(dialog_id); + if (silent) { + Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOff", R.string.ChannelNotifyMembersInfoOff), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOn", R.string.ChannelNotifyMembersInfoOn), Toast.LENGTH_SHORT).show(); + } + } + }); } + recordedAudioPanel = new FrameLayoutFixed(context); + recordedAudioPanel.setVisibility(audioToSend == null ? GONE : VISIBLE); + recordedAudioPanel.setBackgroundColor(0xffffffff); + recordedAudioPanel.setFocusable(true); + recordedAudioPanel.setFocusableInTouchMode(true); + recordedAudioPanel.setClickable(true); + frameLayout.addView(recordedAudioPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(R.drawable.ic_ab_fwd_delete); + recordedAudioPanel.addView(imageView, LayoutHelper.createFrame(48, 48)); + imageView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); + if (playing != null && playing == audioToSendMessageObject) { + MediaController.getInstance().cleanupPlayer(true, true); + } + if (audioToSendPath != null) { + new File(audioToSendPath).delete(); + } + hideRecordedAudioPanel(); + checkSendButton(true); + } + }); + + View view = new View(context); + view.setBackgroundResource(R.drawable.recorded); + recordedAudioPanel.addView(view, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.CENTER_VERTICAL | Gravity.LEFT, 48, 0, 0, 0)); + + recordedAudioSeekBar = new SeekBarWaveformView(context); + recordedAudioPanel.addView(recordedAudioSeekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.CENTER_VERTICAL | Gravity.LEFT, 48 + 44, 0, 52, 0)); + + recordedAudioPlayButton = new ImageView(context); + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + recordedAudioPlayButton.setScaleType(ImageView.ScaleType.CENTER); + recordedAudioPanel.addView(recordedAudioPlayButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.BOTTOM, 48, 0, 0, 0)); + recordedAudioPlayButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (audioToSend == null) { + return; + } + if (MediaController.getInstance().isPlayingAudio(audioToSendMessageObject) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(audioToSendMessageObject); + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + } else { + recordedAudioPlayButton.setImageResource(R.drawable.s_player_pause_states); + MediaController.getInstance().playAudio(audioToSendMessageObject); + } + } + }); + + recordedAudioTimeTextView = new TextView(context); + recordedAudioTimeTextView.setTextColor(0xffffffff); + recordedAudioTimeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + recordedAudioTimeTextView.setText("0:13"); + recordedAudioPanel.addView(recordedAudioTimeTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 13, 0)); + recordPanel = new FrameLayoutFixed(context); recordPanel.setVisibility(GONE); recordPanel.setBackgroundColor(0xffffffff); @@ -595,7 +762,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat slideText.setOrientation(LinearLayout.HORIZONTAL); recordPanel.addView(slideText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 30, 0, 0, 0)); - ImageView imageView = new ImageView(context); + imageView = new ImageView(context); imageView.setImageResource(R.drawable.slidearrow); slideText.addView(imageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); @@ -620,8 +787,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat recordTimeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); linearLayout.addView(recordTimeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 6, 0, 0, 0)); - FrameLayout frameLayout1 = new FrameLayout(context); - textFieldContainer.addView(frameLayout1, LayoutHelper.createLinear(48, 48, Gravity.BOTTOM)); + sendButtonContainer = new FrameLayout(context); + textFieldContainer.addView(sendButtonContainer, LayoutHelper.createLinear(48, 48, Gravity.BOTTOM)); audioSendButton = new ImageView(context); audioSendButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); @@ -629,7 +796,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat audioSendButton.setBackgroundColor(0xffffffff); audioSendButton.setSoundEffectsEnabled(false); audioSendButton.setPadding(0, 0, AndroidUtilities.dp(4), 0); - frameLayout1.addView(audioSendButton, LayoutHelper.createFrame(48, 48)); + sendButtonContainer.addView(audioSendButton, LayoutHelper.createFrame(48, 48)); audioSendButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { @@ -664,13 +831,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat audioSendButton.getParent().requestDisallowInterceptTouchEvent(true); } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { startedDraggingX = -1; - MediaController.getInstance().stopRecording(true); + MediaController.getInstance().stopRecording(1); recordingAudio = false; updateAudioRecordIntefrace(); } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudio) { float x = motionEvent.getX(); if (x < -distCanMove) { - MediaController.getInstance().stopRecording(false); + MediaController.getInstance().stopRecording(0); recordingAudio = false; updateAudioRecordIntefrace(); } @@ -727,7 +894,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat ViewProxy.setScaleY(sendButton, 0.1f); ViewProxy.setAlpha(sendButton, 0.0f); sendButton.clearAnimation(); - frameLayout1.addView(sendButton, LayoutHelper.createFrame(48, 48)); + sendButtonContainer.addView(sendButton, LayoutHelper.createFrame(48, 48)); sendButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -787,6 +954,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } public void setAllowStickersAndGifs(boolean value, boolean value2) { + if ((allowStickers != value || allowGifs != value2) && emojiView != null) { + if (emojiView.getVisibility() == VISIBLE) { + hidePopup(false); + } + sizeNotifierLayout.removeView(emojiView); + emojiView = null; + } allowStickers = value; allowGifs = value2; } @@ -824,7 +998,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat public void onAnimationEnd(Object animation) { if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) { setTopViewAnimation(1.0f); - if (!forceShowSendButton || openKeyboard) { + if (recordedAudioPanel.getVisibility() != VISIBLE && (!forceShowSendButton || openKeyboard)) { openKeyboard(); } currentTopViewAnimation = null; @@ -835,7 +1009,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat currentTopViewAnimation.start(); } else { setTopViewAnimation(1.0f); - if (!forceShowSendButton || openKeyboard) { + if (recordedAudioPanel.getVisibility() != VISIBLE && (!forceShowSendButton || openKeyboard)) { openKeyboard(); } } @@ -925,6 +1099,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidSent); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioRouteChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged); + if (emojiView != null) { + emojiView.onDestroy(); + } if (mWakeLock != null) { try { mWakeLock.release(); @@ -961,8 +1140,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat dialog_id = id; if ((int) dialog_id < 0) { TLRPC.Chat currentChat = MessagesController.getInstance().getChat(-(int) dialog_id); + silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + dialog_id, false); isAsAdmin = ChatObject.isChannel(currentChat) && (currentChat.creator || currentChat.editor) && !currentChat.megagroup; adminModeAvailable = isAsAdmin && !currentChat.broadcast; + canWriteToChannel = isAsAdmin; if (adminModeAvailable) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); isAsAdmin = preferences.getBoolean("asadmin_" + dialog_id, true); @@ -972,6 +1153,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat asAdminButton.setImageResource(isAsAdmin ? R.drawable.publish_active : R.drawable.publish); updateFieldHint(); } + if (notifyButton != null) { + notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE); + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + ViewProxy.setPivotX(attachButton, AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); + } } } @@ -982,7 +1168,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat isChannel = ChatObject.isChannel(chat) && !chat.megagroup; } if (isChannel) { - messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment)); + if (editingMessageObject != null) { + messageEditText.setHint(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage)); + } else { + messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment)); + } } else { messageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage)); } @@ -1013,6 +1203,26 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat return messageWebPageSearch; } + private void hideRecordedAudioPanel() { + audioToSendPath = null; + audioToSend = null; + audioToSendMessageObject = null; + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether( + ObjectAnimatorProxy.ofFloat(recordedAudioPanel, "alpha", 0.0f) + ); + animatorSetProxy.setDuration(200); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + recordedAudioPanel.clearAnimation(); + recordedAudioPanel.setVisibility(View.GONE); + + } + }); + animatorSetProxy.start(); + } + private void sendMessage() { if (parentFragment != null) { String action; @@ -1031,6 +1241,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat return; } } + if (audioToSend != null) { + MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); + if (playing != null && playing == audioToSendMessageObject) { + MediaController.getInstance().cleanupPlayer(true, true); + } + SendMessagesHelper.getInstance().sendMessage(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, isAsAdmin, null); + if (delegate != null) { + delegate.onMessageSend(null); + } + hideRecordedAudioPanel(); + checkSendButton(true); + return; + } String message = messageEditText.getText().toString(); if (processSendingText(message)) { messageEditText.setText(""); @@ -1045,6 +1268,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } + public void doneEditingMessage() { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance().editMessage(editingMessageObject, messageEditText.getText().toString(), messageWebPageSearch, parentFragment); + setEditinigMessageObject(null, false); + } + } + public boolean processSendingText(String text) { text = getTrimmedString(text); if (text.length() != 0) { @@ -1073,8 +1303,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } private void checkSendButton(final boolean animated) { + if (editingMessageObject != null) { + return; + } String message = getTrimmedString(messageEditText.getText().toString()); - if (message.length() > 0 || forceShowSendButton) { + if (message.length() > 0 || forceShowSendButton || audioToSend != null) { if (audioSendButton.getVisibility() == View.VISIBLE) { if (animated) { if (runningAnimationType == 1) { @@ -1109,7 +1342,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat updateFieldRight(0); - delegate.onAttachButtonHidden(); + if (delegate != null) { + delegate.onAttachButtonHidden(); + } } sendButton.setVisibility(View.VISIBLE); @@ -1152,7 +1387,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (attachButton != null) { attachButton.setVisibility(View.GONE); attachButton.clearAnimation(); - delegate.onAttachButtonHidden(); + if (delegate != null) { + delegate.onAttachButtonHidden(); + } updateFieldRight(0); } } @@ -1234,19 +1471,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } private void updateFieldRight(int attachVisible) { - if (messageEditText == null) { + if (messageEditText == null || editingMessageObject != null) { return; } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) messageEditText.getLayoutParams(); if (attachVisible == 1) { - if (botButton != null && botButton.getVisibility() == VISIBLE) { + if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE) { layoutParams.rightMargin = AndroidUtilities.dp(98); } else { layoutParams.rightMargin = AndroidUtilities.dp(50); } } else if (attachVisible == 2) { if (layoutParams.rightMargin != AndroidUtilities.dp(2)) { - if (botButton != null && botButton.getVisibility() == VISIBLE) { + if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE) { layoutParams.rightMargin = AndroidUtilities.dp(98); } else { layoutParams.rightMargin = AndroidUtilities.dp(50); @@ -1369,6 +1606,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat messageEditText.setText(text); messageEditText.setSelection(messageEditText.getText().length()); ignoreTextChange = false; + if (delegate != null) { + delegate.onTextChanged(messageEditText.getText(), true); + } if (!keyboardVisible && currentPopupContentType == -1) { openKeyboard(); } @@ -1382,7 +1622,66 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } - public void setFieldText(String text) { + public void setEditinigMessageObject(MessageObject messageObject, boolean caption) { + if (audioToSend != null || editingMessageObject == messageObject) { + return; + } + editingMessageObject = messageObject; + editingCaption = caption; + if (editingMessageObject != null) { + InputFilter[] inputFilters = new InputFilter[1]; + if (caption) { + inputFilters[0] = new InputFilter.LengthFilter(200); + if (editingMessageObject.caption != null) { + setFieldText(Emoji.replaceEmoji(new SpannableStringBuilder(editingMessageObject.caption.toString()), messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); + } else { + setFieldText(""); + } + } else { + inputFilters[0] = new InputFilter.LengthFilter(4096); + if (editingMessageObject.messageText != null) { + setFieldText(Emoji.replaceEmoji(new SpannableStringBuilder(editingMessageObject.messageText.toString()), messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); + } else { + setFieldText(""); + } + } + messageEditText.setFilters(inputFilters); + openKeyboard(); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) messageEditText.getLayoutParams(); + layoutParams.rightMargin = AndroidUtilities.dp(4); + messageEditText.setLayoutParams(layoutParams); + sendButton.clearAnimation(); + audioSendButton.clearAnimation(); + attachButton.clearAnimation(); + sendButtonContainer.clearAnimation(); + sendButton.setVisibility(GONE); + audioSendButton.setVisibility(GONE); + attachButton.setVisibility(GONE); + sendButtonContainer.setVisibility(GONE); + } else { + messageEditText.setFilters(new InputFilter[0]); + delegate.onMessageEditEnd(); + audioSendButton.setVisibility(VISIBLE); + attachButton.setVisibility(VISIBLE); + sendButtonContainer.setVisibility(VISIBLE); + ViewProxy.setScaleX(attachButton, 1.0f); + ViewProxy.setAlpha(attachButton, 1.0f); + ViewProxy.setScaleX(sendButton, 0.1f); + ViewProxy.setScaleY(sendButton, 0.1f); + ViewProxy.setAlpha(sendButton, 0.0f); + ViewProxy.setScaleX(audioSendButton, 1.0f); + ViewProxy.setScaleY(audioSendButton, 1.0f); + ViewProxy.setAlpha(audioSendButton, 1.0f); + sendButton.setVisibility(View.GONE); + sendButton.clearAnimation(); + messageEditText.setText(""); + delegate.onAttachButtonShow(); + updateFieldRight(1); + } + updateFieldHint(); + } + + public void setFieldText(CharSequence text) { if (messageEditText == null) { return; } @@ -1489,7 +1788,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat botButton.setVisibility(GONE); } updateFieldRight(2); - ViewProxy.setPivotX(attachButton, AndroidUtilities.dp(botButton.getVisibility() == GONE ? 48 : 96)); + ViewProxy.setPivotX(attachButton, AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); attachButton.clearAnimation(); } @@ -1621,7 +1920,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override public void onGifSelected(TLRPC.Document gif) { - SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) gif, null, dialog_id, replyingMessageObject, asAdmin(), null); + SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) gif, null, null, dialog_id, replyingMessageObject, asAdmin(), null); if (delegate != null) { delegate.onMessageSend(null); } @@ -1759,6 +2058,14 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } + public boolean isEditingMessage() { + return editingMessageObject != null; + } + + public boolean isEditingCaption() { + return editingCaption; + } + public void openKeyboard() { AndroidUtilities.showKeyboard(messageEditText); } @@ -1868,8 +2175,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat botKeyboardView.invalidateViews(); } } else if (id == NotificationCenter.recordProgressChanged) { - Long time = (Long) args[0] / 1000; - String str = String.format("%02d:%02d", time / 60, time % 60); + long t = (Long) args[0]; + Long time = t / 1000; + int ms = (int) (t % 1000L) / 10; + String str = String.format("%02d:%02d.%02d", time / 60, time % 60, ms); if (lastTimeString == null || !lastTimeString.equals(str)) { if (time % 5 == 0) { MessagesController.getInstance().sendTyping(dialog_id, 1, 0); @@ -1897,14 +2206,77 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat updateAudioRecordIntefrace(); } } else if (id == NotificationCenter.audioDidSent) { - if (delegate != null) { - delegate.onMessageSend(null); + audioToSend = (TLRPC.TL_document) args[0]; + audioToSendPath = (String) args[1]; + if (audioToSend != null) { + if (recordedAudioPanel == null) { + return; + } + + TLRPC.TL_message message = new TLRPC.TL_message(); + message.out = true; + message.id = 0; + message.to_id = new TLRPC.TL_peerUser(); + message.to_id.user_id = message.from_id = UserConfig.getClientUserId(); + message.date = (int) (System.currentTimeMillis() / 1000); + message.message = "-1"; + message.attachPath = audioToSendPath; + message.media = new TLRPC.TL_messageMediaDocument(); + message.media.document = audioToSend; + message.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + audioToSendMessageObject = new MessageObject(message, null, false); + + ViewProxy.setAlpha(recordedAudioPanel, 1.0f); + recordedAudioPanel.clearAnimation(); + recordedAudioPanel.setVisibility(VISIBLE); + int duration = 0; + for (int a = 0; a < audioToSend.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = audioToSend.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + + for (int a = 0; a < audioToSend.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = audioToSend.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.waveform == null || attribute.waveform.length == 0) { + attribute.waveform = MediaController.getInstance().getWaveform(audioToSendPath); + } + recordedAudioSeekBar.setWaveform(attribute.waveform); + break; + } + } + recordedAudioTimeTextView.setText(String.format("%d:%02d", duration / 60, duration % 60)); + closeKeyboard(); + hidePopup(false); + checkSendButton(false); + } else { + if (delegate != null) { + delegate.onMessageSend(null); + } } } else if (id == NotificationCenter.audioRouteChanged) { if (parentActivity != null) { boolean frontSpeaker = (Boolean) args[0]; parentActivity.setVolumeControlStream(frontSpeaker ? AudioManager.STREAM_VOICE_CALL : AudioManager.USE_DEFAULT_STREAM_TYPE); } + } else if (id == NotificationCenter.audioDidReset) { + if (audioToSendMessageObject != null && !MediaController.getInstance().isPlayingAudio(audioToSendMessageObject)) { + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + recordedAudioSeekBar.setProgress(0); + } + } else if (id == NotificationCenter.audioProgressDidChanged) { + Integer mid = (Integer) args[0]; + if (audioToSendMessageObject != null && MediaController.getInstance().isPlayingAudio(audioToSendMessageObject)) { + MessageObject player = MediaController.getInstance().getPlayingMessageObject(); + audioToSendMessageObject.audioProgress = player.audioProgress; + audioToSendMessageObject.audioProgressSec = player.audioProgressSec; + if (!recordedAudioSeekBar.isDragging()) { + recordedAudioSeekBar.setProgress(audioToSendMessageObject.audioProgress); + } + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java index 00dbf0795..97a47121f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java @@ -173,7 +173,7 @@ public class ChatAttachView extends FrameLayout implements NotificationCenter.No LocaleController.getString("ChatCamera", R.string.ChatCamera), LocaleController.getString("ChatGallery", R.string.ChatGallery), LocaleController.getString("ChatVideo", R.string.ChatVideo), - LocaleController.getString("AttachAudio", R.string.AttachAudio), + LocaleController.getString("AttachMusic", R.string.AttachMusic), LocaleController.getString("ChatDocument", R.string.ChatDocument), LocaleController.getString("AttachContact", R.string.AttachContact), LocaleController.getString("ChatLocation", R.string.ChatLocation), 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 6363e5855..7877474c2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -488,7 +488,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private HashMap emojiUseHistory = new HashMap<>(); private static HashMap emojiColor = new HashMap<>(); private ArrayList recentEmoji = new ArrayList<>(); - private HashMap stickersUseHistory = new HashMap<>(); + private ArrayList newRecentStickers = new ArrayList<>(); private ArrayList recentStickers = new ArrayList<>(); private ArrayList stickerSets = new ArrayList<>(); private ArrayList recentImages; @@ -518,8 +518,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private FlowLayoutManager flowLayoutManager; private GifsAdapter gifsAdapter; private AdapterView.OnItemClickListener stickersOnItemClickListener; - private Runnable openStickerPreviewRunnable; - private StickerEmojiCell currentStickerPreviewCell; + + private EmojiColorPickerView pickerView; private EmojiPopupWindow pickerViewPopup; private int popupWidth; @@ -531,8 +531,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private int gifTabBum = -2; private boolean switchToGifTab; - private int startX; - private int startY; + private int oldWidth; private int lastNotifyWidth; @@ -572,45 +571,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersGridView = new GridView(context) { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int count = stickersGridView.getChildCount(); - for (int a = 0; a < count; a++) { - View view = stickersGridView.getChildAt(a); - int top = view.getTop(); - int bottom = view.getBottom(); - int left = view.getLeft(); - int right = view.getRight(); - if (top > y || bottom < y || left > x || right < x) { - continue; - } - if (!(view instanceof StickerEmojiCell) || !((StickerEmojiCell) view).showingBitmap()) { - return super.onInterceptTouchEvent(event); - } - startX = x; - startY = y; - currentStickerPreviewCell = (StickerEmojiCell) view; - openStickerPreviewRunnable = new Runnable() { - @Override - public void run() { - if (openStickerPreviewRunnable == null) { - return; - } - stickersGridView.setOnItemClickListener(null); - stickersGridView.requestDisallowInterceptTouchEvent(true); - openStickerPreviewRunnable = null; - StickerPreviewViewer.getInstance().setParentActivity((Activity) getContext()); - StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight()); - StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker()); - currentStickerPreviewCell.setScaled(true); - } - }; - AndroidUtilities.runOnUIThread(openStickerPreviewRunnable, 200); - return true; - } - } - return false; + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, stickersGridView, EmojiView.this.getMeasuredHeight()); + return super.onInterceptTouchEvent(event) || result; } @Override @@ -633,67 +595,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersGridView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - if (openStickerPreviewRunnable != null || StickerPreviewViewer.getInstance().isVisible()) { - if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - stickersGridView.setOnItemClickListener(stickersOnItemClickListener); - } - }, 150); - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } else if (StickerPreviewViewer.getInstance().isVisible()) { - StickerPreviewViewer.getInstance().close(); - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } - } - } else if (event.getAction() != MotionEvent.ACTION_DOWN) { - if (StickerPreviewViewer.getInstance().isVisible()) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int count = stickersGridView.getChildCount(); - for (int a = 0; a < count; a++) { - View view = stickersGridView.getChildAt(a); - int top = view.getTop(); - int bottom = view.getBottom(); - int left = view.getLeft(); - int right = view.getRight(); - if (top > y || bottom < y || left > x || right < x) { - continue; - } - if (!(view instanceof StickerEmojiCell) || view == currentStickerPreviewCell) { - break; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - } - currentStickerPreviewCell = (StickerEmojiCell) view; - StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight()); - StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker()); - currentStickerPreviewCell.setScaled(true); - return true; - } - } - return true; - } else if (openStickerPreviewRunnable != null) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(10)) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - } else { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - } - } - } - return false; + return StickerPreviewViewer.getInstance().onTouch(event, stickersGridView, EmojiView.this.getMeasuredHeight(), stickersOnItemClickListener); } }); stickersOnItemClickListener = new AdapterView.OnItemClickListener() { @@ -702,35 +604,23 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (!(view instanceof StickerEmojiCell)) { return; } - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } + StickerPreviewViewer.getInstance().reset(); StickerEmojiCell cell = (StickerEmojiCell) view; if (cell.isDisabled()) { return; } cell.disable(); TLRPC.Document document = cell.getSticker(); - Integer count = stickersUseHistory.get(document.id); - if (count == null) { - count = 0; - } - if (count == 0 && stickersUseHistory.size() > 19) { - for (int a = recentStickers.size() - 1; a >= 0; a--) { - TLRPC.Document sticker = recentStickers.get(a); - stickersUseHistory.remove(sticker.id); - recentStickers.remove(a); - if (stickersUseHistory.size() <= 19) { - break; - } + int index = newRecentStickers.indexOf(document.id); + if (index == -1) { + newRecentStickers.add(0, document.id); + if (newRecentStickers.size() > 20) { + newRecentStickers.remove(newRecentStickers.size() - 1); } + } else if (index != 0) { + newRecentStickers.remove(index); + newRecentStickers.add(0, document.id); } - stickersUseHistory.put(document.id, ++count); saveRecentStickers(); if (listener != null) { @@ -763,12 +653,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific break; } } - if (size.width == 0) { - size.width = 100; - } - if (size.height == 0) { - size.height = 100; - } return size; } }); @@ -821,7 +705,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.show(); + builder.show().setCanceledOnTouchOutside(true); return true; } }); @@ -1213,16 +1097,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private void saveRecentStickers() { SharedPreferences.Editor editor = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE).edit(); StringBuilder stringBuilder = new StringBuilder(); - for (HashMap.Entry entry : stickersUseHistory.entrySet()) { + for (int a = 0; a < newRecentStickers.size(); a++) { if (stringBuilder.length() != 0) { stringBuilder.append(","); } - stringBuilder.append(entry.getKey()); - stringBuilder.append("="); - stringBuilder.append(entry.getValue()); + stringBuilder.append(newRecentStickers.get(a)); } - editor.putString("stickers", stringBuilder.toString()); - + editor.putString("stickers2", stringBuilder.toString()); editor.commit(); } @@ -1270,43 +1151,28 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return; } recentStickers.clear(); - HashMap hashMap = new HashMap<>(); - for (HashMap.Entry entry : stickersUseHistory.entrySet()) { - TLRPC.Document sticker = StickersQuery.getStickerById(entry.getKey()); + for (int a = 0; a < newRecentStickers.size(); a++) { + TLRPC.Document sticker = StickersQuery.getStickerById(newRecentStickers.get(a)); if (sticker != null) { recentStickers.add(sticker); - hashMap.put(sticker.id, entry.getValue()); } } - if (stickersUseHistory.size() != hashMap.size()) { - stickersUseHistory = hashMap; - saveRecentStickers(); - } - Collections.sort(recentStickers, new Comparator() { - @Override - public int compare(TLRPC.Document lhs, TLRPC.Document rhs) { - Integer count1 = stickersUseHistory.get(lhs.id); - Integer count2 = stickersUseHistory.get(rhs.id); - if (count1 == null) { - count1 = 0; - } - if (count2 == null) { - count2 = 0; - } - if (count1 > count2) { - return -1; - } else if (count1 < count2) { - return 1; - } - return 0; - } - }); while (recentStickers.size() > 20) { recentStickers.remove(recentStickers.size() - 1); } + if (newRecentStickers.size() != recentStickers.size()) { + newRecentStickers.clear(); + for (int a = 0; a < recentStickers.size(); a++) { + newRecentStickers.add(recentStickers.get(a).id); + } + saveRecentStickers(); + } } private void updateStickerTabs() { + if (scrollSlidingTabStrip == null) { + return; + } recentTabBum = -2; gifTabBum = -2; @@ -1452,7 +1318,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific str = preferences.getString("color", ""); if (str != null && str.length() > 0) { String[] args = str.split(","); - for (String arg : args) { + for (int a = 0; a < args.length; a++) { + String arg = args[a]; String[] args2 = arg.split("="); emojiColor.put(args2[0], args2[1]); } @@ -1463,13 +1330,44 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (showStickers) { try { - stickersUseHistory.clear(); + newRecentStickers.clear(); str = preferences.getString("stickers", ""); if (str != null && str.length() > 0) { String[] args = str.split(","); - for (String arg : args) { + final HashMap stickersUseHistory = new HashMap<>(); + for (int a = 0; a < args.length; a++) { + String arg = args[a]; String[] args2 = arg.split("="); - stickersUseHistory.put(Long.parseLong(args2[0]), Integer.parseInt(args2[1])); + Long key = Long.parseLong(args2[0]); + stickersUseHistory.put(key, Integer.parseInt(args2[1])); + newRecentStickers.add(key); + } + Collections.sort(newRecentStickers, new Comparator() { + @Override + public int compare(Long lhs, Long rhs) { + Integer count1 = stickersUseHistory.get(lhs); + Integer count2 = stickersUseHistory.get(rhs); + if (count1 == null) { + count1 = 0; + } + if (count2 == null) { + count2 = 0; + } + if (count1 > count2) { + return -1; + } else if (count1 < count2) { + return 1; + } + return 0; + } + }); + preferences.edit().remove("stickers").commit(); + saveRecentStickers(); + } else { + str = preferences.getString("stickers2", ""); + String[] args = str.split(","); + for (int a = 0; a < args.length; a++) { + newRecentStickers.add(Long.parseLong(args[a])); } } sortStickers(); @@ -1518,14 +1416,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (StickerPreviewViewer.getInstance().isVisible()) { StickerPreviewViewer.getInstance().close(); } - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } + StickerPreviewViewer.getInstance().reset(); } public void setListener(Listener value) { @@ -1546,6 +1437,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (stickersGridAdapter != null) { NotificationCenter.getInstance().addObserver(this, NotificationCenter.stickersDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.recentImagesDidLoaded); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updateStickerTabs(); + reloadStickersAdapter(); + } + }); } } @@ -1576,13 +1474,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + public void onDestroy() { if (stickersGridAdapter != null) { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.stickersDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.recentImagesDidLoaded); } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); if (pickerViewPopup != null && pickerViewPopup.isShowing()) { pickerViewPopup.dismiss(); } @@ -1666,7 +1567,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific int previousCount = recentImages != null ? recentImages.size() : 0; recentImages = (ArrayList) args[1]; loadingRecent = false; - gifsAdapter.notifyDataSetChanged(); + if (gifsAdapter != null) { + gifsAdapter.notifyDataSetChanged(); + } if (previousCount != recentImages.size()) { updateStickerTabs(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java index 510c9f65f..4d5d6c418 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java @@ -13,6 +13,8 @@ import android.view.View; import android.view.ViewGroup; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; import org.telegram.messenger.support.widget.RecyclerView; import java.util.ArrayList; @@ -356,11 +358,14 @@ public class FlowLayoutManager extends RecyclerView.LayoutManager { } preferredRowSize = getHeight() / 2.0f; float viewPortAvailableSize = getWidth(); + if (BuildVars.DEBUG_VERSION) { + FileLog.d("tmessages", "preferredRowSize = " + preferredRowSize + " width = " + viewPortAvailableSize); + } float totalItemSize = 0; int[] weights = new int[getItemCount()]; for (int a = 0; a < getItemCount(); a++) { - Size size = getSizeForItem(a); + Size size = sizeForItem(a); totalItemSize += (size.width / size.height) * preferredRowSize; weights[a] = Math.round(size.width / size.height * 100); } @@ -377,7 +382,7 @@ public class FlowLayoutManager extends RecyclerView.LayoutManager { float summedRatios = 0; for (int j = i, n = i + row.size(); j < n; j++) { - Size preferredSize = getSizeForItem(j); + Size preferredSize = sizeForItem(j); summedRatios += preferredSize.width / preferredSize.height; } @@ -392,7 +397,7 @@ public class FlowLayoutManager extends RecyclerView.LayoutManager { } for (int j = i, n = i + row.size(); j < n; j++) { - Size preferredSize = getSizeForItem(j); + Size preferredSize = sizeForItem(j); actualSize.width = Math.round(rowSize / summedRatios * (preferredSize.width / preferredSize.height)); actualSize.height = preferredRowSize;//Math.round(rowSize / summedRatios); @@ -503,7 +508,22 @@ public class FlowLayoutManager extends RecyclerView.LayoutManager { return answer; } + private Size sizeForItem(int i) { + Size size = getSizeForItem(i); + if (size.width == 0) { + size.width = 100; + } + if (size.height == 0) { + size.height = 100; + } + float aspect = size.width / size.height; + if (aspect > 4.0f || aspect < 0.2f) { + size.height = size.width = Math.max(size.width, size.height); + } + return size; + } + protected Size getSizeForItem(int i) { - return new Size(1, 1); + return new Size(100, 100); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java index 0973d69a8..5625ed373 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java @@ -15,7 +15,6 @@ import android.graphics.drawable.Drawable; import org.telegram.messenger.AndroidUtilities; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.Utilities; public class IdenticonDrawable extends Drawable { @@ -35,9 +34,7 @@ public class IdenticonDrawable extends Drawable { public void setEncryptedChat(TLRPC.EncryptedChat encryptedChat) { data = encryptedChat.key_hash; if (data == null) { - byte[] sha1 = Utilities.computeSHA1(encryptedChat.auth_key); - encryptedChat.key_hash = data = new byte[16]; - System.arraycopy(sha1, 0, data, 0, data.length); + encryptedChat.key_hash = data = AndroidUtilities.calcAuthKeyHash(encryptedChat.auth_key); } invalidateSelf(); } @@ -48,17 +45,33 @@ public class IdenticonDrawable extends Drawable { return; } - int bitPointer = 0; - float rectSize = (float)Math.floor(Math.min(getBounds().width(), getBounds().height()) / 8.0f); - float xOffset = Math.max(0, (getBounds().width() - rectSize * 8) / 2); - float yOffset = Math.max(0, (getBounds().height() - rectSize * 8) / 2); - for (int iy = 0; iy < 8; iy++) { - for (int ix = 0; ix < 8; ix++) { - int byteValue = getBits(bitPointer); - bitPointer += 2; - int colorIndex = Math.abs(byteValue) % 4; - paint.setColor(colors[colorIndex]); - canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + if (data.length == 16) { + int bitPointer = 0; + float rectSize = (float) Math.floor(Math.min(getBounds().width(), getBounds().height()) / 8.0f); + float xOffset = Math.max(0, (getBounds().width() - rectSize * 8) / 2); + float yOffset = Math.max(0, (getBounds().height() - rectSize * 8) / 2); + for (int iy = 0; iy < 8; iy++) { + for (int ix = 0; ix < 8; ix++) { + int byteValue = getBits(bitPointer); + bitPointer += 2; + int colorIndex = Math.abs(byteValue) % 4; + paint.setColor(colors[colorIndex]); + canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + } + } + } else { + int bitPointer = 0; + float rectSize = (float) Math.floor(Math.min(getBounds().width(), getBounds().height()) / 12.0f); + float xOffset = Math.max(0, (getBounds().width() - rectSize * 12) / 2); + float yOffset = Math.max(0, (getBounds().height() - rectSize * 12) / 2); + for (int iy = 0; iy < 12; iy++) { + for (int ix = 0; ix < 12; ix++) { + int byteValue = getBits(bitPointer); + int colorIndex = Math.abs(byteValue) % 4; + paint.setColor(colors[colorIndex]); + canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + bitPointer += 2; + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java index eb9b8ed3d..3c12182b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java @@ -80,6 +80,132 @@ public class PhotoCropView extends FrameLayout { requestLayout(); } + public void setOrientation(int rotation) { + orientation = rotation; + rectX = -1; + rectY = -1; + rectSizeX = 600; + rectSizeY = 600; + delegate.needMoveImageTo(0, 0, 1, false); + requestLayout(); + + /*float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14); + float bitmapStartY = (getHeight() - AndroidUtilities.dp(28) - bitmapScaledHeight) / 2 + bitmapGlobalY + AndroidUtilities.dp(14); + + float percSizeX = rectSizeX / bitmapScaledWidth; + float percSizeY = rectSizeY / bitmapScaledHeight; + float percX = (rectX - bitmapStartX) / bitmapScaledWidth + percSizeX; + float percY = (rectY - bitmapStartY) / bitmapScaledHeight; + + int width; + int height; + if (orientation % 360 == 90 || orientation % 360 == 270) { + width = bitmapToEdit.getHeight(); + height = bitmapToEdit.getWidth(); + } else { + width = bitmapToEdit.getWidth(); + height = bitmapToEdit.getHeight(); + } + + int x = (int) (percX * width); + int y = (int) (percY * height); + int sizeX = (int) (percSizeX * width); + int sizeY = (int) (percSizeY * height); + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x + sizeX > width) { + sizeX = width - x; + } + if (y + sizeY > height) { + sizeY = height - y; + } + + double cx = (x + sizeX) - width / 2.0f; + double cy = y - height / 2.0f; + double newX = cx * Math.cos(-Math.PI / 2) - cy * Math.sin(-Math.PI / 2) + height / 2.0f; + double newY = cx * Math.sin(-Math.PI / 2) + cy * Math.cos(-Math.PI / 2) + width / 2.0f; + int temp = sizeX; + sizeY = sizeY; + sizeY = temp;*/ + + + + /*int temp = bitmapWidth; + orientation = rotation; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + + rectX = (float) (newX * bitmapScaledWidth); + rectY = (float) (newX * bitmapScaledHeight); + float temp2 = rectSizeX; + rectSizeX = rectSizeY; + rectSizeY = temp2; + + moveToFill(false); + invalidate();*/ + + /*float temp = rectX; + rectX = rectY; + rectY = temp; + temp = rectSizeX; + rectSizeX = rectSizeY; + rectSizeY = temp; + int temp2 = bitmapWidth;*/ + //requestLayout(); + + /* + bitmapWidth = bitmapHeight; + bitmapHeight = temp2;*/ + + /*float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14); + float bitmapStartY = (getHeight() - AndroidUtilities.dp(28) - bitmapScaledHeight) / 2 + bitmapGlobalY + AndroidUtilities.dp(14); + + float percX = (rectX - bitmapStartX) / bitmapScaledWidth; + float percY = (rectY - bitmapStartY) / bitmapScaledHeight; + float percSizeX = rectSizeX / bitmapScaledWidth; + float percSizeY = rectSizeY / bitmapScaledHeight; + + rectX = percY + + int width; + int height; + if (orientation % 360 == 90 || orientation % 360 == 270) { + width = bitmapToEdit.getHeight(); + height = bitmapToEdit.getWidth(); + } else { + width = bitmapToEdit.getWidth(); + height = bitmapToEdit.getHeight(); + } + + int x = (int) (percX * width); + int y = (int) (percY * height); + int sizeX = (int) (percSizeX * width); + int sizeY = (int) (percSizeY * height); + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x + sizeX > width) { + sizeX = width - x; + } + if (y + sizeY > height) { + sizeY = height - y; + }*/ + //moveToFill(false); + } + public boolean onTouch(MotionEvent motionEvent) { if (motionEvent == null) { draggingState = 0; @@ -353,7 +479,7 @@ public class PhotoCropView extends FrameLayout { Matrix matrix = new Matrix(); matrix.setTranslate(-bitmapToEdit.getWidth() / 2, -bitmapToEdit.getHeight() / 2); matrix.postRotate(orientation); - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { matrix.postTranslate(bitmapToEdit.getHeight() / 2 - x, bitmapToEdit.getWidth() / 2 - y); } else { matrix.postTranslate(bitmapToEdit.getWidth() / 2 - x, bitmapToEdit.getHeight() / 2 - y); @@ -381,7 +507,7 @@ public class PhotoCropView extends FrameLayout { int width; int height; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { width = bitmapToEdit.getHeight(); height = bitmapToEdit.getWidth(); } else { @@ -467,7 +593,7 @@ public class PhotoCropView extends FrameLayout { public void run() { if (animationRunnable == this) { animationRunnable = null; - animateToFill(); + moveToFill(true); } } }; @@ -502,7 +628,7 @@ public class PhotoCropView extends FrameLayout { } } - public void animateToFill() { + public void moveToFill(boolean animated) { float scaleToX = bitmapWidth / rectSizeX; float scaleToY = bitmapHeight / rectSizeY; float scaleTo = scaleToX > scaleToY ? scaleToY : scaleToX; @@ -521,7 +647,7 @@ public class PhotoCropView extends FrameLayout { float newBitmapGlobalX = newX + getWidth() / 2 * (scaleTo - 1) + (bitmapGlobalX - rectX) * scaleTo; float newBitmapGlobalY = newY + getHeight() / 2 * (scaleTo - 1) + (bitmapGlobalY - rectY) * scaleTo; - delegate.needMoveImageTo(newBitmapGlobalX, newBitmapGlobalY, bitmapGlobalScale * scaleTo, true); + delegate.needMoveImageTo(newBitmapGlobalX, newBitmapGlobalY, bitmapGlobalScale * scaleTo, animated); } public void setDelegate(PhotoCropViewDelegate delegate) { @@ -541,7 +667,7 @@ public class PhotoCropView extends FrameLayout { float bitmapW; float bitmapH; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { bitmapW = bitmapToEdit.getHeight(); bitmapH = bitmapToEdit.getWidth(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java index d7e3d11da..1c81798da 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java @@ -61,7 +61,7 @@ public class PhotoFilterBlurControl extends FrameLayout { private float pointerScale = 1; private boolean isMoving; private boolean isZooming; - private boolean checkForMoving; + private boolean checkForMoving = true; private boolean checkForZooming; private int type; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java new file mode 100644 index 000000000..8946a24f0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java @@ -0,0 +1,322 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.text.TextPaint; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; + +import java.util.Locale; + +public class PhotoFilterCurvesControl extends View { + + public interface PhotoFilterCurvesControlDelegate { + void valueChanged(); + } + + private final static int CurvesSegmentNone = 0; + private final static int CurvesSegmentBlacks = 1; + private final static int CurvesSegmentShadows = 2; + private final static int CurvesSegmentMidtones = 3; + private final static int CurvesSegmentHighlights = 4; + private final static int CurvesSegmentWhites = 5; + + private final static int GestureStateBegan = 1; + private final static int GestureStateChanged = 2; + private final static int GestureStateEnded = 3; + private final static int GestureStateCancelled = 4; + private final static int GestureStateFailed = 5; + + private int activeSegment = CurvesSegmentNone; + + private boolean isMoving; + private boolean checkForMoving = true; + + private float lastX; + private float lastY; + + private Rect actualArea = new Rect(); + + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint paintDash = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint paintCurve = new Paint(Paint.ANTI_ALIAS_FLAG); + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private Path path = new Path(); + + private PhotoFilterCurvesControlDelegate delegate; + + private PhotoFilterView.CurvesToolValue curveValue; + + public PhotoFilterCurvesControl(Context context, PhotoFilterView.CurvesToolValue value) { + super(context); + setWillNotDraw(false); + + curveValue = value; + + paint.setColor(0x99ffffff); + paint.setStrokeWidth(AndroidUtilities.dp(1)); + paint.setStyle(Paint.Style.STROKE); + + paintDash.setColor(0x99ffffff); + paintDash.setStrokeWidth(AndroidUtilities.dp(2)); + paintDash.setStyle(Paint.Style.STROKE); + + paintCurve.setColor(0xffffffff); + paintCurve.setStrokeWidth(AndroidUtilities.dp(2)); + paintCurve.setStyle(Paint.Style.STROKE); + + textPaint.setColor(0xffbfbfbf); + textPaint.setTextSize(AndroidUtilities.dp(13)); + } + + public void setDelegate(PhotoFilterCurvesControlDelegate photoFilterCurvesControlDelegate) { + delegate = photoFilterCurvesControlDelegate; + } + + public void setActualArea(float x, float y, float width, float height) { + actualArea.x = x; + actualArea.y = y; + actualArea.width = width; + actualArea.height = height; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_DOWN: { + if (event.getPointerCount() == 1) { + if (checkForMoving && !isMoving) { + float locationX = event.getX(); + float locationY = event.getY(); + lastX = locationX; + lastY = locationY; + if (locationX >= actualArea.x && locationX <= actualArea.x + actualArea.width && locationY >= actualArea.y && locationY <= actualArea.y + actualArea.height) { + isMoving = true; + } + checkForMoving = false; + if (isMoving) { + handlePan(GestureStateBegan, event); + } + } + } else { + if (isMoving) { + handlePan(GestureStateEnded, event); + checkForMoving = true; + isMoving = false; + } + } + break; + } + + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + if (isMoving) { + handlePan(GestureStateEnded, event); + isMoving = false; + } + checkForMoving = true; + break; + } + + case MotionEvent.ACTION_MOVE: { + if (isMoving) { + handlePan(GestureStateChanged, event); + } + } + } + return true; + } + + private void handlePan(int state, MotionEvent event) { + float locationX = event.getX(); + float locationY = event.getY(); + + switch (state) { + case GestureStateBegan: { + selectSegmentWithPoint(locationX); + break; + } + + case GestureStateChanged: { + float delta = Math.min(2, (lastY - locationY) / 8.0f); + + PhotoFilterView.CurvesValue curveValue = null; + switch (this.curveValue.activeType) { + case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance: + curveValue = this.curveValue.luminanceCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeRed: + curveValue = this.curveValue.redCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeGreen: + curveValue = this.curveValue.greenCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeBlue: + curveValue = this.curveValue.blueCurve; + break; + + default: + break; + } + + switch (activeSegment) { + case CurvesSegmentBlacks: + curveValue.blacksLevel = Math.max(0, Math.min(100, curveValue.blacksLevel + delta)); + break; + + case CurvesSegmentShadows: + curveValue.shadowsLevel = Math.max(0, Math.min(100, curveValue.shadowsLevel + delta)); + break; + + case CurvesSegmentMidtones: + curveValue.midtonesLevel = Math.max(0, Math.min(100, curveValue.midtonesLevel + delta)); + break; + + case CurvesSegmentHighlights: + curveValue.highlightsLevel = Math.max(0, Math.min(100, curveValue.highlightsLevel + delta)); + break; + + case CurvesSegmentWhites: + curveValue.whitesLevel = Math.max(0, Math.min(100, curveValue.whitesLevel + delta)); + break; + + default: + break; + } + + invalidate(); + + if (delegate != null) { + delegate.valueChanged(); + } + + lastX = locationX; + lastY = locationY; + } + break; + + case GestureStateEnded: + case GestureStateCancelled: + case GestureStateFailed: { + unselectSegments(); + } + break; + + default: + break; + } + } + + private void selectSegmentWithPoint(float pointx) { + if (activeSegment != CurvesSegmentNone) { + return; + } + float segmentWidth = actualArea.width / 5.0f; + pointx -= actualArea.x; + activeSegment = (int) Math.floor((pointx / segmentWidth) + 1); + } + + private void unselectSegments() { + if (activeSegment == CurvesSegmentNone) { + return; + } + activeSegment = CurvesSegmentNone; + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + float segmentWidth = actualArea.width / 5.0f; + + for (int i = 0; i < 4; i++) { + canvas.drawLine(actualArea.x + segmentWidth + i * segmentWidth, actualArea.y, actualArea.x + segmentWidth + i * segmentWidth, actualArea.y + actualArea.height, paint); + } + + canvas.drawLine(actualArea.x, actualArea.y + actualArea.height, actualArea.x + actualArea.width, actualArea.y, paintDash); + + PhotoFilterView.CurvesValue curvesValue = null; + switch (curveValue.activeType) { + case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance: + paintCurve.setColor(0xffffffff); + curvesValue = curveValue.luminanceCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeRed: + paintCurve.setColor(0xffed3d4c); + curvesValue = curveValue.redCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeGreen: + paintCurve.setColor(0xff10ee9d); + curvesValue = curveValue.greenCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeBlue: + paintCurve.setColor(0xff3377fb); + curvesValue = curveValue.blueCurve; + break; + + default: + break; + } + + for (int a = 0; a < 5; a++) { + String str; + switch (a) { + case 0: + str = String.format(Locale.US, "%.2f", curvesValue.blacksLevel / 100.0f); + break; + case 1: + str = String.format(Locale.US, "%.2f", curvesValue.shadowsLevel / 100.0f); + break; + case 2: + str = String.format(Locale.US, "%.2f", curvesValue.midtonesLevel / 100.0f); + break; + case 3: + str = String.format(Locale.US, "%.2f", curvesValue.highlightsLevel / 100.0f); + break; + case 4: + str = String.format(Locale.US, "%.2f", curvesValue.whitesLevel / 100.0f); + break; + default: + str = ""; + break; + } + float width = textPaint.measureText(str); + canvas.drawText(str, actualArea.x + (segmentWidth - width) / 2 + segmentWidth * a, actualArea.y + actualArea.height - AndroidUtilities.dp(4), textPaint); + } + + float[] points = curvesValue.interpolateCurve(); + invalidate(); + path.reset(); + for (int a = 0; a < points.length / 2; a++) { + if (a == 0) { + path.moveTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height); + } else { + path.lineTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height); + } + } + + canvas.drawPath(path, paintCurve); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java index 0ecb1b689..2eb4445a1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java @@ -25,6 +25,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; @@ -44,6 +45,7 @@ import org.telegram.ui.Cells.PhotoEditToolCell; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; +import java.util.ArrayList; import java.util.concurrent.Semaphore; import javax.microedition.khronos.egl.EGL10; @@ -57,9 +59,35 @@ import javax.microedition.khronos.opengles.GL10; @SuppressLint("NewApi") public class PhotoFilterView extends FrameLayout { + private final int[] tintShadowColors = new int[] { + 0x00000000, + 0xffff4d4d, + 0xfff48022, + 0xffffcd00, + 0xff81d281, + 0xff71c5d6, + 0xff0072bc, + 0xff662d91 + }; + + private final int[] tintHighlighsColors = new int[] { + 0x00000000, + 0xffef9286, + 0xffeacea2, + 0xfff2e17c, + 0xffa4edae, + 0xff89dce5, + 0xff2e8bc8, + 0xffcd98e5 + }; + private boolean showOriginal; private float previousValue; + private int previousValueInt; + private int previousValueInt2; + + private int selectedTintMode; private int selectedTool = -1; private int enhanceTool = 0; @@ -67,24 +95,35 @@ public class PhotoFilterView extends FrameLayout { private int contrastTool = 2; private int warmthTool = 3; private int saturationTool = 4; - private int highlightsTool = 5; - private int shadowsTool = 6; - private int vignetteTool = 7; - private int grainTool = 8; - private int blurTool = 9; - private int sharpenTool = 10; + private int tintTool = 5; + private int fadeTool = 6; + private int highlightsTool = 7; + private int shadowsTool = 8; + private int vignetteTool = 9; + private int grainTool = 10; + private int blurTool = 11; + private int sharpenTool = 12; + private int curvesTool = 13; - private float highlightsValue = 0; //0 100 - private float contrastValue = 0; //-100 100 - private float shadowsValue = 0; //0 100 - private float exposureValue = 0; //-100 100 private float enhanceValue = 0; //0 100 - private float saturationValue = 0; //-100 100 + private float exposureValue = 0; //-100 100 + private float contrastValue = 0; //-100 100 private float warmthValue = 0; //-100 100 + private float saturationValue = 0; //-100 100 + private float fadeValue = 0; // 0 100 + private int tintShadowsColor = 0; //0 0xffffffff + private int tintHighlightsColor = 0; //0 0xffffffff + private float highlightsValue = 0; //-100 100 + private float shadowsValue = 0; //-100 100 private float vignetteValue = 0; //0 100 private float grainValue = 0; //0 100 - private float sharpenValue = 0; //0 100 private int blurType = 0; //0 none, 1 radial, 2 linear + private float sharpenValue = 0; //0 100 + private CurvesToolValue curvesToolValue = new CurvesToolValue(); + + private final static int curveGranularity = 100; + private final static int curveDataStep = 2; + private float blurExcludeSize = 0.35f; private Point blurExcludePoint = new Point(0.5f, 0.5f); private float blurExcludeBlurSize = 0.15f; @@ -95,7 +134,7 @@ public class PhotoFilterView extends FrameLayout { private FrameLayout toolsView; private FrameLayout editView; private TextView paramTextView; - private TextView blurTextView; + private TextView infoTextView; private TextView valueTextView; private TextView doneTextView; private TextView cancelTextView; @@ -104,13 +143,169 @@ public class PhotoFilterView extends FrameLayout { private RecyclerListView recyclerListView; private FrameLayout blurLayout; private PhotoFilterBlurControl blurControl; + private PhotoFilterCurvesControl curvesControl; private TextView blurOffButton; private TextView blurRadialButton; private TextView blurLinearButton; + private FrameLayout tintLayout; + private TextView tintShadowsButton; + private TextView tintHighlightsButton; + private LinearLayout tintButtonsContainer; + private FrameLayout curveLayout; + private TextView[] curveTextView = new TextView[4]; private Bitmap bitmapToEdit; private int orientation; + public static class CurvesValue { + + public float blacksLevel = 0.0f; + public float shadowsLevel = 25.0f; + public float midtonesLevel = 50.0f; + public float highlightsLevel = 75.0f; + public float whitesLevel = 100.0f; + + public float previousBlacksLevel = 0.0f; + public float previousShadowsLevel = 25.0f; + public float previousMidtonesLevel = 50.0f; + public float previousHighlightsLevel = 75.0f; + public float previousWhitesLevel = 100.0f; + + public float[] cachedDataPoints; + + public float[] getDataPoints() { + if (cachedDataPoints == null) { + interpolateCurve(); + } + return cachedDataPoints; + } + + public void saveValues() { + previousBlacksLevel = blacksLevel; + previousShadowsLevel = shadowsLevel; + previousMidtonesLevel = midtonesLevel; + previousHighlightsLevel = highlightsLevel; + previousWhitesLevel = whitesLevel; + } + + public void restoreValues() { + blacksLevel = previousBlacksLevel; + shadowsLevel = previousShadowsLevel; + midtonesLevel = previousMidtonesLevel; + highlightsLevel = previousHighlightsLevel; + whitesLevel = previousWhitesLevel; + interpolateCurve(); + } + + public float[] interpolateCurve() { + float[] points = new float[] { + -0.001f, blacksLevel / 100.0f, + 0.0f, blacksLevel / 100.0f, + 0.25f, shadowsLevel / 100.0f, + 0.5f, midtonesLevel / 100.0f, + 0.75f, highlightsLevel / 100.0f, + 1f, whitesLevel / 100.0f, + 1.001f, whitesLevel / 100.0f + }; + + ArrayList dataPoints = new ArrayList<>(100); + ArrayList interpolatedPoints = new ArrayList<>(100); + + interpolatedPoints.add(points[0]); + interpolatedPoints.add(points[1]); + + for (int index = 1; index < points.length / 2 - 2; index++) { + float point0x = points[(index - 1) * 2]; + float point0y = points[(index - 1) * 2 + 1]; + float point1x = points[(index) * 2]; + float point1y = points[(index) * 2 + 1]; + float point2x = points[(index + 1) * 2]; + float point2y = points[(index + 1) * 2 + 1]; + float point3x = points[(index + 2) * 2]; + float point3y = points[(index + 2) * 2 + 1]; + + + for (int i = 1; i < curveGranularity; i++) { + float t = (float) i * (1.0f / (float) curveGranularity); + float tt = t * t; + float ttt = tt * t; + + float pix = 0.5f * (2 * point1x + (point2x - point0x) * t + (2 * point0x - 5 * point1x + 4 * point2x - point3x) * tt + (3 * point1x - point0x - 3 * point2x + point3x) * ttt); + float piy = 0.5f * (2 * point1y + (point2y - point0y) * t + (2 * point0y - 5 * point1y + 4 * point2y - point3y) * tt + (3 * point1y - point0y - 3 * point2y + point3y) * ttt); + + piy = Math.max(0, Math.min(1, piy)); + + if (pix > point0x) { + interpolatedPoints.add(pix); + interpolatedPoints.add(piy); + } + + if ((i - 1) % curveDataStep == 0) { + dataPoints.add(piy); + } + } + interpolatedPoints.add(point2x); + interpolatedPoints.add(point2y); + } + interpolatedPoints.add(points[12]); + interpolatedPoints.add(points[13]); + + cachedDataPoints = new float[dataPoints.size()]; + for (int a = 0; a < cachedDataPoints.length; a++) { + cachedDataPoints[a] = dataPoints.get(a); + } + float[] retValue = new float[interpolatedPoints.size()]; + for (int a = 0; a < retValue.length; a++) { + retValue[a] = interpolatedPoints.get(a); + } + return retValue; + } + + public boolean isDefault() { + return Math.abs(blacksLevel - 0) < 0.00001 && Math.abs(shadowsLevel - 25) < 0.00001 && Math.abs(midtonesLevel - 50) < 0.00001 && Math.abs(highlightsLevel - 75) < 0.00001 && Math.abs(whitesLevel - 100) < 0.00001; + } + } + + public static class CurvesToolValue { + + public CurvesValue luminanceCurve = new CurvesValue(); + public CurvesValue redCurve = new CurvesValue(); + public CurvesValue greenCurve = new CurvesValue(); + public CurvesValue blueCurve = new CurvesValue(); + public ByteBuffer curveBuffer = null; + + public int activeType; + + public final static int CurvesTypeLuminance = 0; + public final static int CurvesTypeRed = 1; + public final static int CurvesTypeGreen = 2; + public final static int CurvesTypeBlue = 3; + + public CurvesToolValue() { + curveBuffer = ByteBuffer.allocateDirect(200 * 4); + curveBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + + public void fillBuffer() { + curveBuffer.position(0); + float[] luminanceCurveData = luminanceCurve.getDataPoints(); + float[] redCurveData = redCurve.getDataPoints(); + float[] greenCurveData = greenCurve.getDataPoints(); + float[] blueCurveData = blueCurve.getDataPoints(); + for (int a = 0; a < 200; a++) { + curveBuffer.put((byte) (redCurveData[a] * 255)); + curveBuffer.put((byte) (greenCurveData[a] * 255)); + curveBuffer.put((byte) (blueCurveData[a] * 255)); + curveBuffer.put((byte) (luminanceCurveData[a] * 255)); + } + curveBuffer.position(0); + } + + public boolean shouldBeSkipped() { + return luminanceCurve.isDefault() && redCurve.isDefault() && greenCurve.isDefault() && blueCurve.isDefault(); + } + } + public class EGLThread extends DispatchQueue { private final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; @@ -141,18 +336,26 @@ public class PhotoFilterView extends FrameLayout { private int toolsShaderProgram; private int positionHandle; - private int inputTexCoordHandle; - private int sourceImageHandle; - private int shadowsHandle; - private int highlightsHandle; - private int exposureHandle; - private int contrastHandle; - private int saturationHandle; - private int warmthHandle; - private int vignetteHandle; - private int grainHandle; - private int widthHandle; - private int heightHandle; + private int inputTexCoordHandle; //"varying vec2 texCoord;" + + private int sourceImageHandle; //"uniform sampler2D sourceImage;" + + private int shadowsHandle; //"uniform float shadows;" + + private int highlightsHandle; //"uniform float highlights;" + + private int exposureHandle; //"uniform float exposure;" + + private int contrastHandle; //"uniform float contrast;" + + private int saturationHandle; //"uniform float saturation;" + + private int warmthHandle; //"uniform float warmth;" + + private int vignetteHandle; //"uniform float vignette;" + + private int grainHandle; //"uniform float grain;" + + private int widthHandle; //"uniform float width;" + + private int heightHandle; //"uniform float height;" + + + private int curvesImageHandle; //"uniform sampler2D curvesImage;" + + private int skipToneHandle; //"uniform lowp float skipTone;" + + private int fadeAmountHandle; //"uniform lowp float fadeAmount;" + + private int shadowsTintIntensityHandle; //"uniform lowp float shadowsTintIntensity;" + + private int highlightsTintIntensityHandle; //"uniform lowp float highlightsTintIntensity;" + + private int shadowsTintColorHandle; //"uniform lowp vec3 shadowsTintColor;" + + private int highlightsTintColorHandle; //"uniform lowp vec3 highlightsTintColor;" + private int blurShaderProgram; private int blurPositionHandle; @@ -198,6 +401,7 @@ public class PhotoFilterView extends FrameLayout { private int[] enhanceTextures = new int[2]; private int[] renderTexture = new int[3]; private int[] renderFrameBuffer = new int[3]; + private int[] curveTextures = new int[1]; private boolean hsvGenerated; private int renderBufferWidth; private int renderBufferHeight; @@ -213,6 +417,8 @@ public class PhotoFilterView extends FrameLayout { private final static int PGPhotoEnhanceHistogramBins = 256; private final static int PGPhotoEnhanceSegments = 4; + private long lastRenderCallTime; + private static final String radialBlurFragmentShaderCode = "varying highp vec2 texCoord;" + "uniform sampler2D sourceImage;" + @@ -402,105 +608,285 @@ public class PhotoFilterView extends FrameLayout { "gl_FragColor = result;" + "}"; + /* private static final String toolsFragmentShaderCode = - "precision highp float;" + - "varying vec2 texCoord;" + - "uniform float inputWidth;" + - "uniform float inputHeight;" + + "varying highp vec2 texCoord;" + "uniform sampler2D sourceImage;" + - "uniform float shadows;" + - "uniform float width;" + - "uniform float height;" + - "const vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + - "uniform float highlights;" + - "uniform float exposure;" + - "uniform float contrast;" + - "const vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + - "uniform float saturation;" + - "uniform float warmth;" + - "uniform float grain;" + - "const float permTexUnit = 1.0 / 256.0;" + - "const float permTexUnitHalf = 0.5 / 256.0;" + - "const float grainsize = 2.3;" + - "uniform float vignette;" + - "float getLuma(vec3 rgbP) { " + - "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b); " + + "uniform highp float width;" + + "uniform highp float height;" + + "uniform lowp float rgbCurveValues[200];" + + "uniform lowp float redCurveValues[200];" + + "uniform lowp float greenCurveValues[200];" + + "uniform lowp float blueCurveValues[200];" + + "uniform lowp float skipTone;" + + "uniform lowp float shadows;" + + "const mediump vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + + "uniform lowp float highlights;" + + "uniform lowp float contrast;" + + "uniform lowp float fadeAmount;" + + "const mediump vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + + "uniform lowp float saturation;" + + "uniform lowp float shadowsTintIntensity;" + + "uniform lowp float highlightsTintIntensity;" + + "uniform lowp vec3 shadowsTintColor;" + + "uniform lowp vec3 highlightsTintColor;" + + "uniform lowp float exposure;" + + "uniform lowp float warmth;" + + "uniform lowp float grain;" + + "const lowp float permTexUnit = 1.0 / 256.0;" + + "const lowp float permTexUnitHalf = 0.5 / 256.0;" + + "const lowp float grainsize = 2.3;" + + "uniform lowp float vignette;" + + "highp float getLuma(highp vec3 rgbP) {" + + "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b);" + "}" + - "vec3 rgbToYuv(vec3 inP) {" + - "vec3 outP;" + + "lowp vec3 rgbToHsv(lowp vec3 c) {" + + "highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);" + + "highp vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);" + + "highp vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);" + + "highp float d = q.x - min(q.w, q.y);" + + "highp float e = 1.0e-10;" + + "return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);" + + "}" + + "lowp vec3 hsvToRgb(lowp vec3 c) {" + + "highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" + + "highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" + + "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" + + "}" + + "highp vec3 rgbToHsl(highp vec3 color) {" + + "highp vec3 hsl;" + + "highp float fmin = min(min(color.r, color.g), color.b);" + + "highp float fmax = max(max(color.r, color.g), color.b);" + + "highp float delta = fmax - fmin;" + + "hsl.z = (fmax + fmin) / 2.0;" + + "if (delta == 0.0) {" + + "hsl.x = 0.0;" + + "hsl.y = 0.0;" + + "} else {" + + "if (hsl.z < 0.5) {" + + "hsl.y = delta / (fmax + fmin);" + + "} else {" + + "hsl.y = delta / (2.0 - fmax - fmin);" + + "}" + + "highp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;" + + "if (color.r == fmax) {" + + "hsl.x = deltaB - deltaG;" + + "} else if (color.g == fmax) {" + + "hsl.x = (1.0 / 3.0) + deltaR - deltaB;" + + "} else if (color.b == fmax) {" + + "hsl.x = (2.0 / 3.0) + deltaG - deltaR;" + + "}" + + "if (hsl.x < 0.0) {" + + "hsl.x += 1.0;" + + "} else if (hsl.x > 1.0) {" + + "hsl.x -= 1.0;" + + "}" + + "}" + + "return hsl;" + + "}" + + "highp float hueToRgb(highp float f1, highp float f2, highp float hue) {" + + "if (hue < 0.0) {" + + "hue += 1.0;" + + "} else if (hue > 1.0) {" + + "hue -= 1.0;" + + "}" + + "highp float res;" + + "if ((6.0 * hue) < 1.0) {" + + "res = f1 + (f2 - f1) * 6.0 * hue;" + + "} else if ((2.0 * hue) < 1.0) {" + + "res = f2;" + + "} else if ((3.0 * hue) < 2.0) {" + + "res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;" + + "} else {" + + "res = f1;" + + "} return res;" + + "}" + + "highp vec3 hslToRgb(highp vec3 hsl) {" + + "highp vec3 rgb;" + + "if (hsl.y == 0.0) {" + + "rgb = vec3(hsl.z);" + + "} else {" + + "highp float f2;" + + "if (hsl.z < 0.5) {" + + "f2 = hsl.z * (1.0 + hsl.y);" + + "} else {" + + "f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);" + + "}" + + "highp float f1 = 2.0 * hsl.z - f2;" + + "rgb.r = hueToRgb(f1, f2, hsl.x + (1.0/3.0));" + + "rgb.g = hueToRgb(f1, f2, hsl.x);" + + "rgb.b = hueToRgb(f1, f2, hsl.x - (1.0/3.0));" + + "}" + + "return rgb;" + + "}" + + "highp vec3 rgbToYuv(highp vec3 inP) {" + + "highp vec3 outP;" + "outP.r = getLuma(inP);" + "outP.g = (1.0 / 1.772) * (inP.b - outP.r);" + "outP.b = (1.0 / 1.402) * (inP.r - outP.r);" + - "return outP; " + + "return outP;" + "}" + - "vec3 yuvToRgb(vec3 inP) {" + - "return vec3(1.402 * inP.b + inP.r, (inP.r - (0.299 * 1.402 / 0.587) * inP.b - (0.114 * 1.772 / 0.587) * inP.g), 1.772 * inP.g + inP.r);" + + "lowp vec3 yuvToRgb(highp vec3 inP) {" + + "highp float y = inP.r;" + + "highp float u = inP.g;" + + "highp float v = inP.b;" + + "lowp vec3 outP;" + + "outP.r = 1.402 * v + y;" + + "outP.g = (y - (0.299 * 1.402 / 0.587) * v - (0.114 * 1.772 / 0.587) * u);" + + "outP.b = 1.772 * u + y;" + + "return outP;" + "}" + - "float easeInOutSigmoid(float value, float strength) {" + - "float t = 1.0 / (1.0 - strength);" + + "lowp float easeInOutSigmoid(lowp float value, lowp float strength) {" + + "lowp float t = 1.0 / (1.0 - strength);" + "if (value > 0.5) {" + "return 1.0 - pow(2.0 - 2.0 * value, t) * 0.5;" + "} else {" + - "return pow(2.0 * value, t) * 0.5; " + + "return pow(2.0 * value, t) * 0.5;" + "}" + "}" + - "vec4 rnm(in vec2 tc) {" + - "float noise = sin(dot(tc,vec2(12.9898,78.233))) * 43758.5453;" + - "float noiseR = fract(noise)*2.0-1.0;" + - "float noiseG = fract(noise*1.2154)*2.0-1.0;" + - "float noiseB = fract(noise*1.3453)*2.0-1.0;" + - "float noiseA = fract(noise*1.3647)*2.0-1.0;" + + "lowp vec3 applyLuminanceCurve(lowp vec3 pixel) {" + + "int index = int(clamp(pixel.z / (1.0 / 200.0), 0.0, 199.0));" + + "highp float value = rgbCurveValues[index];" + + "highp float grayscale = (smoothstep(0.0, 0.1, pixel.z) * (1.0 - smoothstep(0.8, 1.0, pixel.z)));" + + "highp float saturation = mix(0.0, pixel.y, grayscale);" + + "pixel.y = saturation;" + + "pixel.z = value;" + + "return pixel;" + + "}" + + "lowp vec3 applyRGBCurve(lowp vec3 pixel) {" + + "int index = int(clamp(pixel.r / (1.0 / 200.0), 0.0, 199.0));" + + "highp float value = redCurveValues[index];" + + "pixel.r = value;" + + "index = int(clamp(pixel.g / (1.0 / 200.0), 0.0, 199.0));" + + "value = greenCurveValues[index];" + + "pixel.g = clamp(value, 0.0, 1.0);" + + "index = int(clamp(pixel.b / (1.0 / 200.0), 0.0, 199.0));" + + "value = blueCurveValues[index];" + + "pixel.b = clamp(value, 0.0, 1.0);" + + "return pixel;" + + "}" + + "highp vec3 fadeAdjust(highp vec3 color, highp float fadeVal) {" + + "highp vec3 co1 = vec3(-0.9772);" + + "highp vec3 co2 = vec3(1.708);" + + "highp vec3 co3 = vec3(-0.1603);" + + "highp vec3 co4 = vec3(0.2878);" + + "highp vec3 comp1 = co1 * pow(vec3(color), vec3(3.0));" + + "highp vec3 comp2 = co2 * pow(vec3(color), vec3(2.0));" + + "highp vec3 comp3 = co3 * vec3(color);" + + "highp vec3 comp4 = co4;" + + "highp vec3 finalComponent = comp1 + comp2 + comp3 + comp4;" + + "highp vec3 difference = finalComponent - color;" + + "highp vec3 scalingValue = vec3(0.9);" + + "highp vec3 faded = color + (difference * scalingValue);" + + "return (color * (1.0 - fadeVal)) + (faded * fadeVal);" + + "}" + + "lowp vec3 tintRaiseShadowsCurve(lowp vec3 color) {" + + "highp vec3 co1 = vec3(-0.003671);" + + "highp vec3 co2 = vec3(0.3842);" + + "highp vec3 co3 = vec3(0.3764);" + + "highp vec3 co4 = vec3(0.2515);" + + "highp vec3 comp1 = co1 * pow(color, vec3(3.0));" + + "highp vec3 comp2 = co2 * pow(color, vec3(2.0));" + + "highp vec3 comp3 = co3 * color;" + + "highp vec3 comp4 = co4;" + + "return comp1 + comp2 + comp3 + comp4;" + + "}" + + "lowp vec3 tintShadows(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "highp vec3 raisedShadows = tintRaiseShadowsCurve(texel);" + + "highp vec3 tintedShadows = mix(texel, raisedShadows, tintColor);" + + "highp vec3 tintedShadowsWithAmount = mix(texel, tintedShadows, tintAmount);" + + "return clamp(tintedShadowsWithAmount, 0.0, 1.0);" + + "} " + + "lowp vec3 tintHighlights(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "lowp vec3 loweredHighlights = vec3(1.0) - tintRaiseShadowsCurve(vec3(1.0) - texel);" + + "lowp vec3 tintedHighlights = mix(texel, loweredHighlights, (vec3(1.0) - tintColor));" + + "lowp vec3 tintedHighlightsWithAmount = mix(texel, tintedHighlights, tintAmount);" + + "return clamp(tintedHighlightsWithAmount, 0.0, 1.0);" + + "}" + + "highp vec4 rnm(in highp vec2 tc) {" + + "highp float noise = sin(dot(tc,vec2(12.9898,78.233))) * 43758.5453;" + + "highp float noiseR = fract(noise)*2.0-1.0;" + + "highp float noiseG = fract(noise*1.2154)*2.0-1.0;" + + "highp float noiseB = fract(noise*1.3453)*2.0-1.0;" + + "highp float noiseA = fract(noise*1.3647)*2.0-1.0;" + "return vec4(noiseR,noiseG,noiseB,noiseA);" + "}" + - "float fade(in float t) {" + + "highp float fade(in highp float t) {" + "return t*t*t*(t*(t*6.0-15.0)+10.0);" + "}" + - "float pnoise3D(in vec3 p) {" + - "vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;" + - "vec3 pf = fract(p);" + - "float perm00 = rnm(pi.xy).a;" + - "vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;" + - "float n000 = dot(grad000, pf);" + - "vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));" + - "float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + - "vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;" + - "float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));" + - "vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));" + - "float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + - "vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;" + - "float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));" + - "vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));" + - "float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + - "vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;" + - "float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));" + - "vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));" + - "vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + - "vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + - "float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));" + + "highp float pnoise3D(in highp vec3 p) {" + + "highp vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;" + + "highp vec3 pf = fract(p);" + + "highp float perm00 = rnm(pi.xy).a;" + + "highp vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n000 = dot(grad000, pf);" + + "highp vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));" + + "highp float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + + "highp vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));" + + "highp vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));" + + "highp float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + + "highp vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));" + + "highp vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));" + + "highp float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + + "highp vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));" + + "highp vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));" + + "highp vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + + "highp vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + + "highp float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));" + "return n_xyz;" + "}" + - "vec2 coordRot(in vec2 tc, in float angle) {" + - "float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));" + - "float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));" + - "return vec2(rotX * 0.5 + 0.5, rotY * 0.5 + 0.5);" + + "lowp vec2 coordRot(in lowp vec2 tc, in lowp float angle) {" + + "lowp float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));" + + "lowp float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));" + + "rotX = rotX * 0.5 + 0.5;" + + "rotY = rotY * 0.5 + 0.5;" + + "return vec2(rotX,rotY);" + "}" + "void main() {" + - "vec4 result = texture2D(sourceImage, texCoord);" + - "const float toolEpsilon = 0.005;" + - - "float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + - "float shadow = clamp((pow(hsLuminance, 1.0 / (shadows + 1.0)) + (-0.76) * pow(hsLuminance, 2.0 / (shadows + 1.0))) - hsLuminance, 0.0, 1.0);" + - "float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + - "vec3 shresult = (hsLuminance + shadow + highlight) * (result.rgb / hsLuminance);" + - "result = vec4(shresult.rgb, result.a);" + - + "lowp vec4 source = texture2D(sourceImage, texCoord);" + + "lowp vec4 result = source;" + + "const lowp float toolEpsilon = 0.005;" + + "if (skipTone < toolEpsilon) {" + + "result = vec4(applyRGBCurve(hslToRgb(applyLuminanceCurve(rgbToHsl(result.rgb)))), result.a);" + + "}" + + "mediump float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + + "mediump float shadow = clamp((pow(hsLuminance, 1.0 / shadows) + (-0.76) * pow(hsLuminance, 2.0 / shadows)) - hsLuminance, 0.0, 1.0);" + + "mediump float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + + "lowp vec3 hsresult = vec3(0.0, 0.0, 0.0) + ((hsLuminance + shadow + highlight) - 0.0) * ((result.rgb - vec3(0.0, 0.0, 0.0)) / (hsLuminance - 0.0));" + + "mediump float contrastedLuminance = ((hsLuminance - 0.5) * 1.5) + 0.5;" + + "mediump float whiteInterp = contrastedLuminance * contrastedLuminance * contrastedLuminance;" + + "mediump float whiteTarget = clamp(highlights, 1.0, 2.0) - 1.0;" + + "hsresult = mix(hsresult, vec3(1.0), whiteInterp * whiteTarget);" + + "mediump float invContrastedLuminance = 1.0 - contrastedLuminance;" + + "mediump float blackInterp = invContrastedLuminance * invContrastedLuminance * invContrastedLuminance;" + + "mediump float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0);" + + "hsresult = mix(hsresult, vec3(0.0), blackInterp * blackTarget);" + + "result = vec4(hsresult.rgb, result.a);" + + "result = vec4(clamp(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), 0.0, 1.0), result.a);" + + "if (abs(fadeAmount) > toolEpsilon) {" + + "result.rgb = fadeAdjust(result.rgb, fadeAmount);" + + "}" + + "lowp float satLuminance = dot(result.rgb, satLuminanceWeighting);" + + "lowp vec3 greyScaleColor = vec3(satLuminance);" + + "result = vec4(clamp(mix(greyScaleColor, result.rgb, saturation), 0.0, 1.0), result.a);" + + "if (abs(shadowsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintShadows(result.rgb, shadowsTintColor, shadowsTintIntensity * 2.0);" + + "}" + + "if (abs(highlightsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintHighlights(result.rgb, highlightsTintColor, highlightsTintIntensity * 2.0);" + + "}" + "if (abs(exposure) > toolEpsilon) {" + - "float mag = exposure * 1.045;" + - "float exppower = 1.0 + abs(mag);" + + "mediump float mag = exposure * 1.045;" + + "mediump float exppower = 1.0 + abs(mag);" + "if (mag < 0.0) {" + "exppower = 1.0 / exppower;" + "}" + @@ -508,41 +894,290 @@ public class PhotoFilterView extends FrameLayout { "result.g = 1.0 - pow((1.0 - result.g), exppower);" + "result.b = 1.0 - pow((1.0 - result.b), exppower);" + "}" + - "result = vec4(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), result.a);" + - "float satLuminance = dot(result.rgb, satLuminanceWeighting);" + - "vec3 greyScaleColor = vec3(satLuminance);" + - "result = vec4(mix(greyScaleColor, result.rgb, saturation), result.a);" + "if (abs(warmth) > toolEpsilon) {" + - "vec3 yuvVec; if (warmth > 0.0 ) {" + + "highp vec3 yuvVec;" + + "if (warmth > 0.0 ) {" + "yuvVec = vec3(0.1765, -0.1255, 0.0902);" + "} else {" + "yuvVec = -vec3(0.0588, 0.1569, -0.1255);" + "}" + - "vec3 yuvColor = rgbToYuv(result.rgb);" + - "float luma = yuvColor.r;" + - "float curveScale = sin(luma * 3.14159);" + + "highp vec3 yuvColor = rgbToYuv(result.rgb);" + + "highp float luma = yuvColor.r;" + + "highp float curveScale = sin(luma * 3.14159);" + "yuvColor += 0.375 * warmth * curveScale * yuvVec;" + "result.rgb = yuvToRgb(yuvColor);" + "}" + "if (abs(grain) > toolEpsilon) {" + - "vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + - "vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + - "vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + - "vec3 lumcoeff = vec3(0.299,0.587,0.114);" + - "float luminance = dot(result.rgb, lumcoeff);" + - "float lum = smoothstep(0.2, 0.0, luminance);" + + "highp vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + + "highp vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + + "highp vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + + "lowp vec3 lumcoeff = vec3(0.299,0.587,0.114);" + + "lowp float luminance = dot(result.rgb, lumcoeff);" + + "lowp float lum = smoothstep(0.2, 0.0, luminance);" + "lum += luminance;" + "noise = mix(noise,vec3(0.0),pow(lum,4.0));" + "result.rgb = result.rgb + noise * grain;" + "}" + "if (abs(vignette) > toolEpsilon) {" + - "const float midpoint = 0.7;" + - "const float fuzziness = 0.62;" + - "float radDist = length(texCoord - 0.5) / sqrt(0.5);" + - "float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + + "const lowp float midpoint = 0.7;" + + "const lowp float fuzziness = 0.62;" + + "lowp float radDist = length(texCoord - 0.5) / sqrt(0.5);" + + "lowp float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + "result.rgb = mix(pow(result.rgb, vec3(1.0 / (1.0 - mag))), vec3(0.0), mag * mag);" + "}" + + "gl_FragColor = result;" + + "}"; + */ + private static final String toolsFragmentShaderCode = + "varying highp vec2 texCoord;" + + "uniform sampler2D sourceImage;" + + "uniform highp float width;" + + "uniform highp float height;" + + "uniform sampler2D curvesImage;" + + "uniform lowp float skipTone;" + + "uniform lowp float shadows;" + + "const mediump vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + + "uniform lowp float highlights;" + + "uniform lowp float contrast;" + + "uniform lowp float fadeAmount;" + + "const mediump vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + + "uniform lowp float saturation;" + + "uniform lowp float shadowsTintIntensity;" + + "uniform lowp float highlightsTintIntensity;" + + "uniform lowp vec3 shadowsTintColor;" + + "uniform lowp vec3 highlightsTintColor;" + + "uniform lowp float exposure;" + + "uniform lowp float warmth;" + + "uniform lowp float grain;" + + "const lowp float permTexUnit = 1.0 / 256.0;" + + "const lowp float permTexUnitHalf = 0.5 / 256.0;" + + "const lowp float grainsize = 2.3;" + + "uniform lowp float vignette;" + + "highp float getLuma(highp vec3 rgbP) {" + + "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b);" + + "}" + + "lowp vec3 rgbToHsv(lowp vec3 c) {" + + "highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);" + + "highp vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);" + + "highp vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);" + + "highp float d = q.x - min(q.w, q.y);" + + "highp float e = 1.0e-10;" + + "return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);" + + "}" + + "lowp vec3 hsvToRgb(lowp vec3 c) {" + + "highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" + + "highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" + + "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" + + "}" + + "highp vec3 rgbToHsl(highp vec3 color) {" + + "highp vec3 hsl;" + + "highp float fmin = min(min(color.r, color.g), color.b);" + + "highp float fmax = max(max(color.r, color.g), color.b);" + + "highp float delta = fmax - fmin;" + + "hsl.z = (fmax + fmin) / 2.0;" + + "if (delta == 0.0) {" + + "hsl.x = 0.0;" + + "hsl.y = 0.0;" + + "} else {" + + "if (hsl.z < 0.5) {" + + "hsl.y = delta / (fmax + fmin);" + + "} else {" + + "hsl.y = delta / (2.0 - fmax - fmin);" + + "}" + + "highp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;" + + "if (color.r == fmax) {" + + "hsl.x = deltaB - deltaG;" + + "} else if (color.g == fmax) {" + + "hsl.x = (1.0 / 3.0) + deltaR - deltaB;" + + "} else if (color.b == fmax) {" + + "hsl.x = (2.0 / 3.0) + deltaG - deltaR;" + + "}" + + "if (hsl.x < 0.0) {" + + "hsl.x += 1.0;" + + "} else if (hsl.x > 1.0) {" + + "hsl.x -= 1.0;" + + "}" + + "}" + + "return hsl;" + + "}" + + "highp float hueToRgb(highp float f1, highp float f2, highp float hue) {" + + "if (hue < 0.0) {" + + "hue += 1.0;" + + "} else if (hue > 1.0) {" + + "hue -= 1.0;" + + "}" + + "highp float res;" + + "if ((6.0 * hue) < 1.0) {" + + "res = f1 + (f2 - f1) * 6.0 * hue;" + + "} else if ((2.0 * hue) < 1.0) {" + + "res = f2;" + + "} else if ((3.0 * hue) < 2.0) {" + + "res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;" + + "} else {" + + "res = f1;" + + "} return res;" + + "}" + + "highp vec3 hslToRgb(highp vec3 hsl) {" + + "if (hsl.y == 0.0) {" + + "return vec3(hsl.z);" + + "} else {" + + "highp float f2;" + + "if (hsl.z < 0.5) {" + + "f2 = hsl.z * (1.0 + hsl.y);" + + "} else {" + + "f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);" + + "}" + + "highp float f1 = 2.0 * hsl.z - f2;" + + "return vec3(hueToRgb(f1, f2, hsl.x + (1.0/3.0)), hueToRgb(f1, f2, hsl.x), hueToRgb(f1, f2, hsl.x - (1.0/3.0)));" + + "}" + + "}" + + "highp vec3 rgbToYuv(highp vec3 inP) {" + + "highp float luma = getLuma(inP);" + + "return vec3(luma, (1.0 / 1.772) * (inP.b - luma), (1.0 / 1.402) * (inP.r - luma));" + + "}" + + "lowp vec3 yuvToRgb(highp vec3 inP) {" + + "return vec3(1.402 * inP.b + inP.r, (inP.r - (0.299 * 1.402 / 0.587) * inP.b - (0.114 * 1.772 / 0.587) * inP.g), 1.772 * inP.g + inP.r);" + + "}" + + "lowp float easeInOutSigmoid(lowp float value, lowp float strength) {" + + "if (value > 0.5) {" + + "return 1.0 - pow(2.0 - 2.0 * value, 1.0 / (1.0 - strength)) * 0.5;" + + "} else {" + + "return pow(2.0 * value, 1.0 / (1.0 - strength)) * 0.5;" + + "}" + + "}" + + "lowp vec3 applyLuminanceCurve(lowp vec3 pixel) {" + + "highp float index = floor(clamp(pixel.z / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.y = mix(0.0, pixel.y, smoothstep(0.0, 0.1, pixel.z) * (1.0 - smoothstep(0.8, 1.0, pixel.z)));" + + "pixel.z = texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).a;" + + "return pixel;" + + "}" + + "lowp vec3 applyRGBCurve(lowp vec3 pixel) {" + + "highp float index = floor(clamp(pixel.r / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.r = texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).r;" + + "index = floor(clamp(pixel.g / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.g = clamp(texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).g, 0.0, 1.0);" + + "index = floor(clamp(pixel.b / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.b = clamp(texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).b, 0.0, 1.0);" + + "return pixel;" + + "}" + + "highp vec3 fadeAdjust(highp vec3 color, highp float fadeVal) {" + + "return (color * (1.0 - fadeVal)) + ((color + (vec3(-0.9772) * pow(vec3(color), vec3(3.0)) + vec3(1.708) * pow(vec3(color), vec3(2.0)) + vec3(-0.1603) * vec3(color) + vec3(0.2878) - color * vec3(0.9))) * fadeVal);" + + "}" + + "lowp vec3 tintRaiseShadowsCurve(lowp vec3 color) {" + + "return vec3(-0.003671) * pow(color, vec3(3.0)) + vec3(0.3842) * pow(color, vec3(2.0)) + vec3(0.3764) * color + vec3(0.2515);" + + "}" + + "lowp vec3 tintShadows(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "return clamp(mix(texel, mix(texel, tintRaiseShadowsCurve(texel), tintColor), tintAmount), 0.0, 1.0);" + + "} " + + "lowp vec3 tintHighlights(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "return clamp(mix(texel, mix(texel, vec3(1.0) - tintRaiseShadowsCurve(vec3(1.0) - texel), (vec3(1.0) - tintColor)), tintAmount), 0.0, 1.0);" + + "}" + + "highp vec4 rnm(in highp vec2 tc) {" + + "highp float noise = sin(dot(tc, vec2(12.9898, 78.233))) * 43758.5453;" + + "return vec4(fract(noise), fract(noise * 1.2154), fract(noise * 1.3453), fract(noise * 1.3647)) * 2.0 - 1.0;" + + "}" + + "highp float fade(in highp float t) {" + + "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);" + + "}" + + "highp float pnoise3D(in highp vec3 p) {" + + "highp vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;" + + "highp vec3 pf = fract(p);" + + "highp float perm = rnm(pi.xy).a;" + + "highp float n000 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf);" + + "highp float n001 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(0.0, 0.0, 1.0));" + + "perm = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + + "highp float n010 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(0.0, 1.0, 0.0));" + + "highp float n011 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(0.0, 1.0, 1.0));" + + "perm = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + + "highp float n100 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(1.0, 0.0, 0.0));" + + "highp float n101 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(1.0, 0.0, 1.0));" + + "perm = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + + "highp float n110 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(1.0, 1.0, 0.0));" + + "highp float n111 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(1.0, 1.0, 1.0));" + + "highp vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + + "highp vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + + "return mix(n_xy.x, n_xy.y, fade(pf.z));" + + "}" + + "lowp vec2 coordRot(in lowp vec2 tc, in lowp float angle) {" + + "return vec2(((tc.x * 2.0 - 1.0) * cos(angle) - (tc.y * 2.0 - 1.0) * sin(angle)) * 0.5 + 0.5, ((tc.y * 2.0 - 1.0) * cos(angle) + (tc.x * 2.0 - 1.0) * sin(angle)) * 0.5 + 0.5);" + + "}" + + "void main() {" + + "lowp vec4 source = texture2D(sourceImage, texCoord);" + + "lowp vec4 result = source;" + + "const lowp float toolEpsilon = 0.005;" + + "if (skipTone < toolEpsilon) {" + + "result = vec4(applyRGBCurve(hslToRgb(applyLuminanceCurve(rgbToHsl(result.rgb)))), result.a);" + + "}" + + "mediump float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + + "mediump float shadow = clamp((pow(hsLuminance, 1.0 / shadows) + (-0.76) * pow(hsLuminance, 2.0 / shadows)) - hsLuminance, 0.0, 1.0);" + + "mediump float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + + "lowp vec3 hsresult = vec3(0.0, 0.0, 0.0) + ((hsLuminance + shadow + highlight) - 0.0) * ((result.rgb - vec3(0.0, 0.0, 0.0)) / (hsLuminance - 0.0));" + + "mediump float contrastedLuminance = ((hsLuminance - 0.5) * 1.5) + 0.5;" + + "mediump float whiteInterp = contrastedLuminance * contrastedLuminance * contrastedLuminance;" + + "mediump float whiteTarget = clamp(highlights, 1.0, 2.0) - 1.0;" + + "hsresult = mix(hsresult, vec3(1.0), whiteInterp * whiteTarget);" + + "mediump float invContrastedLuminance = 1.0 - contrastedLuminance;" + + "mediump float blackInterp = invContrastedLuminance * invContrastedLuminance * invContrastedLuminance;" + + "mediump float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0);" + + "hsresult = mix(hsresult, vec3(0.0), blackInterp * blackTarget);" + + "result = vec4(hsresult.rgb, result.a);" + + "result = vec4(clamp(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), 0.0, 1.0), result.a);" + + "if (abs(fadeAmount) > toolEpsilon) {" + + "result.rgb = fadeAdjust(result.rgb, fadeAmount);" + + "}" + + "lowp float satLuminance = dot(result.rgb, satLuminanceWeighting);" + + "lowp vec3 greyScaleColor = vec3(satLuminance);" + + "result = vec4(clamp(mix(greyScaleColor, result.rgb, saturation), 0.0, 1.0), result.a);" + + "if (abs(shadowsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintShadows(result.rgb, shadowsTintColor, shadowsTintIntensity * 2.0);" + + "}" + + "if (abs(highlightsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintHighlights(result.rgb, highlightsTintColor, highlightsTintIntensity * 2.0);" + + "}" + + "if (abs(exposure) > toolEpsilon) {" + + "mediump float mag = exposure * 1.045;" + + "mediump float exppower = 1.0 + abs(mag);" + + "if (mag < 0.0) {" + + "exppower = 1.0 / exppower;" + + "}" + + "result.r = 1.0 - pow((1.0 - result.r), exppower);" + + "result.g = 1.0 - pow((1.0 - result.g), exppower);" + + "result.b = 1.0 - pow((1.0 - result.b), exppower);" + + "}" + + "if (abs(warmth) > toolEpsilon) {" + + "highp vec3 yuvVec;" + + "if (warmth > 0.0 ) {" + + "yuvVec = vec3(0.1765, -0.1255, 0.0902);" + + "} else {" + + "yuvVec = -vec3(0.0588, 0.1569, -0.1255);" + + "}" + + "highp vec3 yuvColor = rgbToYuv(result.rgb);" + + "highp float luma = yuvColor.r;" + + "highp float curveScale = sin(luma * 3.14159);" + + "yuvColor += 0.375 * warmth * curveScale * yuvVec;" + + "result.rgb = yuvToRgb(yuvColor);" + + "}" + + "if (abs(grain) > toolEpsilon) {" + + "highp vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + + "highp vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + + "highp vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + + "lowp vec3 lumcoeff = vec3(0.299,0.587,0.114);" + + "lowp float luminance = dot(result.rgb, lumcoeff);" + + "lowp float lum = smoothstep(0.2, 0.0, luminance);" + + "lum += luminance;" + + "noise = mix(noise,vec3(0.0),pow(lum,4.0));" + + "result.rgb = result.rgb + noise * grain;" + + "}" + + "if (abs(vignette) > toolEpsilon) {" + + "const lowp float midpoint = 0.7;" + + "const lowp float fuzziness = 0.62;" + + "lowp float radDist = length(texCoord - 0.5) / sqrt(0.5);" + + "lowp float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + + "result.rgb = mix(pow(result.rgb, vec3(1.0 / (1.0 - mag))), vec3(0.0), mag * mag);" + + "}" + "gl_FragColor = result;" + "}"; @@ -559,6 +1194,7 @@ public class PhotoFilterView extends FrameLayout { int[] compileStatus = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); if (compileStatus[0] == 0) { + FileLog.e("tmessages", GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } @@ -671,6 +1307,7 @@ public class PhotoFilterView extends FrameLayout { textureBuffer.put(textureCoordinates); textureBuffer.position(0); + GLES20.glGenTextures(1, curveTextures, 0); GLES20.glGenTextures(2, enhanceTextures, 0); int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, simpleVertexShaderCode); @@ -705,6 +1342,13 @@ public class PhotoFilterView extends FrameLayout { grainHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "grain"); widthHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "width"); heightHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "height"); + curvesImageHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "curvesImage"); + skipToneHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "skipTone"); + fadeAmountHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "fadeAmount"); + shadowsTintIntensityHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "shadowsTintIntensity"); + highlightsTintIntensityHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "highlightsTintIntensity"); + shadowsTintColorHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "shadowsTintColor"); + highlightsTintColorHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "highlightsTintColor"); } } else { finish(); @@ -1032,7 +1676,7 @@ public class PhotoFilterView extends FrameLayout { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTexture[0]); GLES20.glUniform1i(sourceImageHandle, 0); if (showOriginal) { - GLES20.glUniform1f(shadowsHandle, 0); + GLES20.glUniform1f(shadowsHandle, 1); GLES20.glUniform1f(highlightsHandle, 1); GLES20.glUniform1f(exposureHandle, 0); GLES20.glUniform1f(contrastHandle, 1); @@ -1040,6 +1684,12 @@ public class PhotoFilterView extends FrameLayout { GLES20.glUniform1f(warmthHandle, 0); GLES20.glUniform1f(vignetteHandle, 0); GLES20.glUniform1f(grainHandle, 0); + GLES20.glUniform1f(fadeAmountHandle, 0); + GLES20.glUniform3f(highlightsTintColorHandle, 0, 0, 0); + GLES20.glUniform1f(highlightsTintIntensityHandle, 0); + GLES20.glUniform3f(shadowsTintColorHandle, 0, 0, 0); + GLES20.glUniform1f(shadowsTintIntensityHandle, 0); + GLES20.glUniform1f(skipToneHandle, 1); } else { GLES20.glUniform1f(shadowsHandle, getShadowsValue()); GLES20.glUniform1f(highlightsHandle, getHighlightsValue()); @@ -1049,7 +1699,26 @@ public class PhotoFilterView extends FrameLayout { GLES20.glUniform1f(warmthHandle, getWarmthValue()); GLES20.glUniform1f(vignetteHandle, getVignetteValue()); GLES20.glUniform1f(grainHandle, getGrainValue()); + GLES20.glUniform1f(fadeAmountHandle, getFadeValue()); + GLES20.glUniform3f(highlightsTintColorHandle, (tintHighlightsColor >> 16 & 0xff) / 255.0f, (tintHighlightsColor >> 8 & 0xff) / 255.0f, (tintHighlightsColor & 0xff) / 255.0f); + GLES20.glUniform1f(highlightsTintIntensityHandle, getTintHighlightsIntensityValue()); + GLES20.glUniform3f(shadowsTintColorHandle, (tintShadowsColor >> 16 & 0xff) / 255.0f, (tintShadowsColor >> 8 & 0xff) / 255.0f, (tintShadowsColor & 0xff) / 255.0f); + GLES20.glUniform1f(shadowsTintIntensityHandle, getTintShadowsIntensityValue()); + boolean skipTone = curvesToolValue.shouldBeSkipped(); + GLES20.glUniform1f(skipToneHandle, skipTone ? 1.0f : 0.0f); + if (!skipTone) { + curvesToolValue.fillBuffer(); + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GL10.GL_TEXTURE_2D, curveTextures[0]); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 200, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, curvesToolValue.curveBuffer); + GLES20.glUniform1i(curvesImageHandle, 1); + } } + GLES20.glUniform1f(widthHandle, renderBufferWidth); GLES20.glUniform1f(heightHandle, renderBufferHeight); GLES20.glEnableVertexAttribArray(inputTexCoordHandle); @@ -1203,36 +1872,17 @@ public class PhotoFilterView extends FrameLayout { } private Bitmap createBitmap(Bitmap bitmap, int w, int h, float scale) { - //Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - //Canvas canvas = new Canvas(result); - //Paint paint = new Paint(); - //paint.setFilterBitmap(true); - Matrix matrix = new Matrix(); matrix.setScale(scale, scale); - //matrix.postTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2); matrix.postRotate(orientation); - /*if (orientation == 90 || orientation == 270) { - matrix.postTranslate(bitmap.getHeight() / 2, bitmap.getWidth() / 2); - } else { - matrix.postTranslate(bitmap.getWidth() / 2, bitmap.getHeight() / 2); - }*/ - //canvas.drawBitmap(bitmap, matrix, paint); - //try { - // canvas.setBitmap(null); - //} catch (Exception e) { - //don't promt, this will crash on 2.x - //} return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - - //return result; } private void loadTexture(Bitmap bitmap) { renderBufferWidth = bitmap.getWidth(); renderBufferHeight = bitmap.getHeight(); float maxSize = AndroidUtilities.getPhotoSize(); - if (renderBufferWidth > maxSize || renderBufferHeight > maxSize || orientation != 0) { + if (renderBufferWidth > maxSize || renderBufferHeight > maxSize || orientation % 360 != 0) { float scale = 1; if (renderBufferWidth > maxSize || renderBufferHeight > maxSize) { float scaleX = maxSize / bitmap.getWidth(); @@ -1248,7 +1898,7 @@ public class PhotoFilterView extends FrameLayout { } } - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { int temp = renderBufferWidth; renderBufferWidth = renderBufferHeight; renderBufferHeight = temp; @@ -1313,8 +1963,13 @@ public class PhotoFilterView extends FrameLayout { if (!needUpdateBlurTexture) { needUpdateBlurTexture = updateBlur; } - cancelRunnable(drawRunnable); - postRunnable(drawRunnable); + long newTime = System.currentTimeMillis(); + if (Math.abs(lastRenderCallTime - newTime) > 30) { + lastRenderCallTime = newTime; + drawRunnable.run(); + //cancelRunnable(drawRunnable); + //postRunnable(drawRunnable, 30); + } } }); } @@ -1331,13 +1986,8 @@ public class PhotoFilterView extends FrameLayout { //setLayerType(LAYER_TYPE_HARDWARE, null); //textureView.setLayerType(LAYER_TYPE_HARDWARE, null); } - addView(textureView); + addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); textureView.setVisibility(INVISIBLE); - LayoutParams layoutParams = (LayoutParams) textureView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - textureView.setLayoutParams(layoutParams); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { @@ -1379,12 +2029,7 @@ public class PhotoFilterView extends FrameLayout { blurControl = new PhotoFilterBlurControl(context); blurControl.setVisibility(INVISIBLE); - addView(blurControl); - layoutParams = (LayoutParams) blurControl.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; - blurControl.setLayoutParams(layoutParams); + addView(blurControl, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); blurControl.setDelegate(new PhotoFilterBlurControl.PhotoFilterLinearBlurControlDelegate() { @Override public void valueChanged(Point centerPoint, float falloff, float size, float angle) { @@ -1398,22 +2043,24 @@ public class PhotoFilterView extends FrameLayout { } }); + curvesControl = new PhotoFilterCurvesControl(context, curvesToolValue); + curvesControl.setDelegate(new PhotoFilterCurvesControl.PhotoFilterCurvesControlDelegate() { + @Override + public void valueChanged() { + if (eglThread != null) { + eglThread.requestRender(false); + } + } + }); + curvesControl.setVisibility(INVISIBLE); + addView(curvesControl, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + toolsView = new FrameLayout(context); - addView(toolsView); - layoutParams = (LayoutParams) toolsView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(126); - layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM; - toolsView.setLayoutParams(layoutParams); + addView(toolsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 126, Gravity.LEFT | Gravity.BOTTOM)); FrameLayout frameLayout = new FrameLayout(context); frameLayout.setBackgroundColor(0xff1a1a1a); - toolsView.addView(frameLayout); - layoutParams = (LayoutParams) frameLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(48); - layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; - frameLayout.setLayoutParams(layoutParams); + toolsView.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); cancelTextView = new TextView(context); cancelTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -1423,12 +2070,7 @@ public class PhotoFilterView extends FrameLayout { cancelTextView.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); cancelTextView.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - frameLayout.addView(cancelTextView); - layoutParams = (LayoutParams) cancelTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - cancelTextView.setLayoutParams(layoutParams); + frameLayout.addView(cancelTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); doneTextView = new TextView(context); doneTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -1438,12 +2080,7 @@ public class PhotoFilterView extends FrameLayout { doneTextView.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); doneTextView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); doneTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - frameLayout.addView(doneTextView); - layoutParams = (LayoutParams) doneTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; - doneTextView.setLayoutParams(layoutParams); + frameLayout.addView(doneTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); recyclerListView = new RecyclerListView(context); LinearLayoutManager layoutManager = new LinearLayoutManager(context); @@ -1454,12 +2091,7 @@ public class PhotoFilterView extends FrameLayout { recyclerListView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); } recyclerListView.setAdapter(toolsAdapter = new ToolsAdapter(context)); - toolsView.addView(recyclerListView); - layoutParams = (FrameLayout.LayoutParams) recyclerListView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; - recyclerListView.setLayoutParams(layoutParams); + toolsView.addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 60, Gravity.LEFT | Gravity.TOP)); recyclerListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { @@ -1470,7 +2102,7 @@ public class PhotoFilterView extends FrameLayout { paramTextView.setText(LocaleController.getString("Enhance", R.string.Enhance)); } else if (position == highlightsTool) { previousValue = highlightsValue; - valueSeekBar.setMinMax(0, 100); + valueSeekBar.setMinMax(-100, 100); paramTextView.setText(LocaleController.getString("Highlights", R.string.Highlights)); } else if (position == contrastTool) { previousValue = contrastValue; @@ -1494,18 +2126,30 @@ public class PhotoFilterView extends FrameLayout { paramTextView.setText(LocaleController.getString("Vignette", R.string.Vignette)); } else if (position == shadowsTool) { previousValue = shadowsValue; - valueSeekBar.setMinMax(0, 100); + valueSeekBar.setMinMax(-100, 100); paramTextView.setText(LocaleController.getString("Shadows", R.string.Shadows)); } else if (position == grainTool) { previousValue = grainValue; valueSeekBar.setMinMax(0, 100); paramTextView.setText(LocaleController.getString("Grain", R.string.Grain)); + } else if (position == fadeTool) { + previousValue = fadeValue; + valueSeekBar.setMinMax(0, 100); + paramTextView.setText(LocaleController.getString("Fade", R.string.Fade)); } else if (position == sharpenTool) { previousValue = sharpenValue; valueSeekBar.setMinMax(0, 100); paramTextView.setText(LocaleController.getString("Sharpen", R.string.Sharpen)); } else if (position == blurTool) { - previousValue = blurType; + previousValueInt = blurType; + } else if (position == tintTool) { + previousValueInt = tintShadowsColor; + previousValueInt2 = tintHighlightsColor; + } else if (position == curvesTool) { + curvesToolValue.luminanceCurve.saveValues(); + curvesToolValue.redCurve.saveValues(); + curvesToolValue.greenCurve.saveValues(); + curvesToolValue.blueCurve.saveValues(); } valueSeekBar.setProgress((int) previousValue, false); updateValueTextView(); @@ -1515,32 +2159,17 @@ public class PhotoFilterView extends FrameLayout { editView = new FrameLayout(context); editView.setVisibility(GONE); - addView(editView); - layoutParams = (LayoutParams) editView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(126); - layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM; - editView.setLayoutParams(layoutParams); + addView(editView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 126, Gravity.LEFT | Gravity.BOTTOM)); frameLayout = new FrameLayout(context); frameLayout.setBackgroundColor(0xff1a1a1a); - editView.addView(frameLayout); - layoutParams = (LayoutParams) frameLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(48); - layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; - frameLayout.setLayoutParams(layoutParams); + editView.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); ImageView imageView = new ImageView(context); imageView.setImageResource(R.drawable.edit_cancel); imageView.setBackgroundResource(R.drawable.bar_selector_picker); imageView.setPadding(AndroidUtilities.dp(22), 0, AndroidUtilities.dp(22), 0); - frameLayout.addView(imageView); - layoutParams = (LayoutParams) imageView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - imageView.setLayoutParams(layoutParams); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1564,8 +2193,18 @@ public class PhotoFilterView extends FrameLayout { grainValue = previousValue; } else if (selectedTool == sharpenTool) { sharpenValue = previousValue; + } else if (selectedTool == fadeTool) { + fadeValue = previousValue; } else if (selectedTool == blurTool) { - blurType = (int) previousValue; + blurType = previousValueInt; + } else if (selectedTool == tintTool) { + tintShadowsColor = previousValueInt; + tintHighlightsColor = previousValueInt2; + } else if (selectedTool == curvesTool) { + curvesToolValue.luminanceCurve.restoreValues(); + curvesToolValue.redCurve.restoreValues(); + curvesToolValue.greenCurve.restoreValues(); + curvesToolValue.blueCurve.restoreValues(); } if (eglThread != null) { eglThread.requestRender(selectedTool != blurTool); @@ -1578,12 +2217,7 @@ public class PhotoFilterView extends FrameLayout { imageView.setImageResource(R.drawable.edit_doneblue); imageView.setBackgroundResource(R.drawable.bar_selector_picker); imageView.setPadding(AndroidUtilities.dp(22), AndroidUtilities.dp(1), AndroidUtilities.dp(22), 0); - frameLayout.addView(imageView); - layoutParams = (LayoutParams) imageView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; - imageView.setLayoutParams(layoutParams); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1592,39 +2226,20 @@ public class PhotoFilterView extends FrameLayout { } }); - blurTextView = new TextView(context); - blurTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - blurTextView.setTextColor(0xffffffff); - blurTextView.setText(LocaleController.getString("Blur", R.string.Blur)); - frameLayout.addView(blurTextView); - layoutParams = (LayoutParams) blurTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(9); - blurTextView.setLayoutParams(layoutParams); + infoTextView = new TextView(context); + infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + infoTextView.setTextColor(0xffffffff); + frameLayout.addView(infoTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); paramTextView = new TextView(context); paramTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); paramTextView.setTextColor(0xff808080); - frameLayout.addView(paramTextView); - layoutParams = (LayoutParams) paramTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(26); - paramTextView.setLayoutParams(layoutParams); + frameLayout.addView(paramTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 26, 0, 0)); valueTextView = new TextView(context); valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); valueTextView.setTextColor(0xffffffff); - frameLayout.addView(valueTextView); - layoutParams = (LayoutParams) valueTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(3); - valueTextView.setLayoutParams(layoutParams); + frameLayout.addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 3, 0, 0)); valueSeekBar = new PhotoEditorSeekBar(context); valueSeekBar.setDelegate(new PhotoEditorSeekBar.PhotoEditorSeekBarDelegate() { @@ -1651,6 +2266,8 @@ public class PhotoFilterView extends FrameLayout { grainValue = progress; } else if (selectedTool == sharpenTool) { sharpenValue = progress; + } else if (selectedTool == fadeTool) { + fadeValue = progress; } updateValueTextView(); if (eglThread != null) { @@ -1658,41 +2275,116 @@ public class PhotoFilterView extends FrameLayout { } } }); - editView.addView(valueSeekBar); - layoutParams = (LayoutParams) valueSeekBar.getLayoutParams(); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(14); - layoutParams.rightMargin = AndroidUtilities.dp(14); - layoutParams.topMargin = AndroidUtilities.dp(10); - if (AndroidUtilities.isTablet()) { - layoutParams.width = AndroidUtilities.dp(498); - layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; - } else { - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; + editView.addView(valueSeekBar, LayoutHelper.createFrame(AndroidUtilities.isTablet() ? 498 : LayoutHelper.MATCH_PARENT, 60, AndroidUtilities.isTablet() ? Gravity.CENTER_HORIZONTAL | Gravity.TOP : Gravity.LEFT | Gravity.TOP, 14, 10, 14, 0)); + + curveLayout = new FrameLayout(context); + editView.addView(curveLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.CENTER_HORIZONTAL)); + + LinearLayout curveTextViewContainer = new LinearLayout(context); + curveTextViewContainer.setOrientation(LinearLayout.HORIZONTAL); + curveLayout.addView(curveTextViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.CENTER_HORIZONTAL)); + + for (int a = 0; a < 4; a++) { + curveTextView[a] = new TextView(context); + curveTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + curveTextView[a].setGravity(Gravity.CENTER_VERTICAL); + curveTextView[a].setTag(a); + if (a == 0) { + curveTextView[a].setText(LocaleController.getString("CurvesAll", R.string.CurvesAll).toUpperCase()); + } else if (a == 1) { + curveTextView[a].setText(LocaleController.getString("CurvesRed", R.string.CurvesRed).toUpperCase()); + } else if (a == 2) { + curveTextView[a].setText(LocaleController.getString("CurvesGreen", R.string.CurvesGreen).toUpperCase()); + } else if (a == 3) { + curveTextView[a].setText(LocaleController.getString("CurvesBlue", R.string.CurvesBlue).toUpperCase()); + } + curveTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + curveTextViewContainer.addView(curveTextView[a], LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, a == 0 ? 0 : 30, 0, 0, 0)); + curveTextView[a].setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int num = (Integer) v.getTag(); + for (int a = 0; a < 4; a++) { + curveTextView[a].setTextColor(a == num ? 0xffffffff : 0xff808080); + } + curvesToolValue.activeType = num; + curvesControl.invalidate(); + } + }); + } + + tintLayout = new FrameLayout(context); + editView.addView(tintLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.CENTER_HORIZONTAL)); + + LinearLayout tintTextViewContainer = new LinearLayout(context); + tintTextViewContainer.setOrientation(LinearLayout.HORIZONTAL); + tintLayout.addView(tintTextViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.CENTER_HORIZONTAL)); + + tintShadowsButton = new TextView(context); + tintShadowsButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tintShadowsButton.setGravity(Gravity.CENTER_VERTICAL); + tintShadowsButton.setText(LocaleController.getString("TintShadows", R.string.TintShadows).toUpperCase()); + tintShadowsButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tintTextViewContainer.addView(tintShadowsButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28)); + tintShadowsButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + selectedTintMode = 0; + updateSelectedTintButton(true); + } + }); + + tintHighlightsButton = new TextView(context); + tintHighlightsButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tintHighlightsButton.setGravity(Gravity.CENTER_VERTICAL); + tintHighlightsButton.setText(LocaleController.getString("TintHighlights", R.string.TintHighlights).toUpperCase()); + tintHighlightsButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tintTextViewContainer.addView(tintHighlightsButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, 100, 0, 0, 0)); + tintHighlightsButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + selectedTintMode = 1; + updateSelectedTintButton(true); + } + }); + + tintButtonsContainer = new LinearLayout(context); + tintButtonsContainer.setOrientation(LinearLayout.HORIZONTAL); + tintButtonsContainer.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); + tintLayout.addView(tintButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.TOP, 0, 24, 0, 0)); + for (int a = 0; a < tintShadowColors.length; a++) { + RadioButton radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setTag(a); + tintButtonsContainer.addView(radioButton, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f / tintShadowColors.length)); + radioButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + RadioButton radioButton = (RadioButton) v; + if (selectedTintMode == 0) { + tintShadowsColor = tintShadowColors[(Integer) radioButton.getTag()]; + } else { + tintHighlightsColor = tintHighlighsColors[(Integer) radioButton.getTag()]; + } + updateSelectedTintButton(true); + if (eglThread != null) { + eglThread.requestRender(false); + } + } + }); } - valueSeekBar.setLayoutParams(layoutParams); blurLayout = new FrameLayout(context); - editView.addView(blurLayout); - layoutParams = (LayoutParams) blurLayout.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(280); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.topMargin = AndroidUtilities.dp(10); - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - blurLayout.setLayoutParams(layoutParams); + editView.addView(blurLayout, LayoutHelper.createFrame(280, 60, Gravity.CENTER_HORIZONTAL, 0, 10, 0, 0)); blurOffButton = new TextView(context); blurOffButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_off_active, 0, 0); + blurOffButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurOffButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurOffButton.setTextColor(0xff51bdf3); blurOffButton.setGravity(Gravity.CENTER_HORIZONTAL); blurOffButton.setText(LocaleController.getString("BlurOff", R.string.BlurOff)); - blurLayout.addView(blurOffButton); - layoutParams = (LayoutParams) blurOffButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - blurOffButton.setLayoutParams(layoutParams); + blurLayout.addView(blurOffButton, LayoutHelper.createFrame(80, 60)); blurOffButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1707,16 +2399,12 @@ public class PhotoFilterView extends FrameLayout { blurRadialButton = new TextView(context); blurRadialButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_radial, 0, 0); + blurRadialButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurRadialButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurRadialButton.setTextColor(0xffffffff); blurRadialButton.setGravity(Gravity.CENTER_HORIZONTAL); blurRadialButton.setText(LocaleController.getString("BlurRadial", R.string.BlurRadial)); - blurLayout.addView(blurRadialButton); - layoutParams = (LayoutParams) blurRadialButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(100); - blurRadialButton.setLayoutParams(layoutParams); + blurLayout.addView(blurRadialButton, LayoutHelper.createFrame(80, 80, Gravity.LEFT | Gravity.TOP, 100, 0, 0, 0)); blurRadialButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1732,16 +2420,12 @@ public class PhotoFilterView extends FrameLayout { blurLinearButton = new TextView(context); blurLinearButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_linear, 0, 0); + blurLinearButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurLinearButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurLinearButton.setTextColor(0xffffffff); blurLinearButton.setGravity(Gravity.CENTER_HORIZONTAL); blurLinearButton.setText(LocaleController.getString("BlurLinear", R.string.BlurLinear)); - blurLayout.addView(blurLinearButton); - layoutParams = (LayoutParams) blurLinearButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(200); - blurLinearButton.setLayoutParams(layoutParams); + blurLayout.addView(blurLinearButton, LayoutHelper.createFrame(80, 80, Gravity.LEFT | Gravity.TOP, 200, 0, 0, 0)); blurLinearButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1781,6 +2465,23 @@ public class PhotoFilterView extends FrameLayout { } } + private void updateSelectedTintButton(boolean animated) { + tintHighlightsButton.setTextColor(selectedTintMode == 1 ? 0xffffffff : 0xff808080); + tintShadowsButton.setTextColor(selectedTintMode == 1 ? 0xff808080 : 0xffffffff); + int childCount = tintButtonsContainer.getChildCount(); + for (int a = 0; a < childCount; a++) { + View child = tintButtonsContainer.getChildAt(a); + if (child instanceof RadioButton) { + RadioButton radioButton = (RadioButton) child; + int num = (Integer) radioButton.getTag(); + int color1 = selectedTintMode == 0 ? tintShadowsColor : tintHighlightsColor; + int color2 = selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num]; + radioButton.setChecked(color1 == color2, animated); + radioButton.setColor(num == 0 ? 0xffffffff : (selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num]), num == 0 ? 0xffffffff : (selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num])); + } + } + } + private void updateValueTextView() { int value = 0; if (selectedTool == enhanceTool) { @@ -1803,6 +2504,8 @@ public class PhotoFilterView extends FrameLayout { value = (int) grainValue; } else if (selectedTool == sharpenTool) { value = (int) sharpenValue; + } else if (selectedTool == fadeTool) { + value = (int) fadeValue; } if (value > 0) { valueTextView.setText("+" + value); @@ -1813,7 +2516,7 @@ public class PhotoFilterView extends FrameLayout { public boolean hasChanges() { return enhanceValue != 0 || contrastValue != 0 || highlightsValue != 0 || exposureValue != 0 || warmthValue != 0 || saturationValue != 0 || vignetteValue != 0 || - shadowsValue != 0 || grainValue != 0 || sharpenValue != 0; + shadowsValue != 0 || grainValue != 0 || sharpenValue != 0 || fadeValue != 0 || tintHighlightsColor != 0 || tintShadowsColor != 0 || !curvesToolValue.shouldBeSkipped(); } public void onTouch(MotionEvent event) { @@ -1844,29 +2547,49 @@ public class PhotoFilterView extends FrameLayout { viewFrom = toolsView; viewTo = editView; - if (selectedTool == blurTool) { - blurLayout.setVisibility(VISIBLE); + if (selectedTool == blurTool || selectedTool == tintTool || selectedTool == curvesTool) { + blurLayout.setVisibility(selectedTool == blurTool ? VISIBLE : INVISIBLE); + tintLayout.setVisibility(selectedTool == tintTool ? VISIBLE : INVISIBLE); + curveLayout.setVisibility(selectedTool == curvesTool ? VISIBLE : INVISIBLE); + if (selectedTool == blurTool) { + infoTextView.setText(LocaleController.getString("Blur", R.string.Blur)); + if (blurType != 0) { + blurControl.setVisibility(VISIBLE); + } + } else if (selectedTool == curvesTool) { + infoTextView.setText(LocaleController.getString("Curves", R.string.Curves)); + curvesControl.setVisibility(VISIBLE); + curvesToolValue.activeType = 0; + for (int a = 0; a < 4; a++) { + curveTextView[a].setTextColor(a == 0 ? 0xffffffff : 0xff808080); + } + } else { + selectedTintMode = 0; + updateSelectedTintButton(false); + infoTextView.setText(LocaleController.getString("Tint", R.string.Tint)); + } + infoTextView.setVisibility(VISIBLE); valueSeekBar.setVisibility(INVISIBLE); - blurTextView.setVisibility(VISIBLE); paramTextView.setVisibility(INVISIBLE); valueTextView.setVisibility(INVISIBLE); - if (blurType != 0) { - blurControl.setVisibility(VISIBLE); - } updateSelectedBlurType(); } else { + tintLayout.setVisibility(INVISIBLE); + curveLayout.setVisibility(INVISIBLE); blurLayout.setVisibility(INVISIBLE); valueSeekBar.setVisibility(VISIBLE); - blurTextView.setVisibility(INVISIBLE); + infoTextView.setVisibility(INVISIBLE); paramTextView.setVisibility(VISIBLE); valueTextView.setVisibility(VISIBLE); blurControl.setVisibility(INVISIBLE); + curvesControl.setVisibility(INVISIBLE); } } else { selectedTool = -1; viewFrom = editView; viewTo = toolsView; blurControl.setVisibility(INVISIBLE); + curvesControl.setVisibility(INVISIBLE); } AnimatorSetProxy animatorSet = new AnimatorSetProxy(); @@ -1928,7 +2651,7 @@ public class PhotoFilterView extends FrameLayout { float bitmapW; float bitmapH; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { bitmapW = bitmapToEdit.getHeight(); bitmapH = bitmapToEdit.getWidth(); } else { @@ -1954,12 +2677,17 @@ public class PhotoFilterView extends FrameLayout { layoutParams.width = (int) bitmapW; layoutParams.height = (int) bitmapH; textureView.setLayoutParams(layoutParams); + curvesControl.setActualArea(bitmapX, bitmapY, layoutParams.width, layoutParams.height); blurControl.setActualAreaSize(layoutParams.width, layoutParams.height); layoutParams = (LayoutParams) blurControl.getLayoutParams(); layoutParams.height = viewHeight + AndroidUtilities.dp(28); blurControl.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) curvesControl.getLayoutParams(); + layoutParams.height = viewHeight + AndroidUtilities.dp(28); + curvesControl.setLayoutParams(layoutParams); + if (AndroidUtilities.isTablet()) { int total = AndroidUtilities.dp(86) * 10; layoutParams = (FrameLayout.LayoutParams) recyclerListView.getLayoutParams(); @@ -1981,11 +2709,11 @@ public class PhotoFilterView extends FrameLayout { } private float getShadowsValue() { - return (shadowsValue / 100.0f) * 0.65f; + return (shadowsValue * 0.55f + 100.0f) / 100.0f; } private float getHighlightsValue() { - return 1 - (highlightsValue / 100.0f); + return (highlightsValue * 0.75f + 100.0f) / 100.0f; } private float getEnhanceValue() { @@ -2016,6 +2744,20 @@ public class PhotoFilterView extends FrameLayout { return grainValue / 100.0f * 0.04f; } + private float getFadeValue() { + return fadeValue / 100.0f; + } + + private float getTintHighlightsIntensityValue() { + float tintHighlightsIntensity = 50.0f; + return tintHighlightsColor == 0 ? 0 : tintHighlightsIntensity / 100.0f; + } + + private float getTintShadowsIntensityValue() { + float tintShadowsIntensity = 50.0f; + return tintShadowsColor == 0 ? 0 : tintShadowsIntensity / 100.0f; + } + private float getSaturationValue() { float parameterValue = (saturationValue / 100.0f); if (parameterValue > 0) { @@ -2078,7 +2820,7 @@ public class PhotoFilterView extends FrameLayout { @Override public int getItemCount() { - return 11; + return 14; } @Override @@ -2115,6 +2857,12 @@ public class PhotoFilterView extends FrameLayout { ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_grain, LocaleController.getString("Grain", R.string.Grain), grainValue); } else if (i == sharpenTool) { ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_details, LocaleController.getString("Sharpen", R.string.Sharpen), sharpenValue); + } else if (i == tintTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_tint, LocaleController.getString("Tint", R.string.Tint), tintHighlightsColor != 0 || tintShadowsColor != 0 ? "◆" : ""); + } else if (i == fadeTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_fade, LocaleController.getString("Fade", R.string.Fade), fadeValue); + } else if (i == curvesTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_curve, LocaleController.getString("Curves", R.string.Curves), curvesToolValue.shouldBeSkipped() ? "" : "◆"); } else if (i == blurTool) { String value = ""; if (blurType == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index 87532d29e..505cbb901 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -22,7 +22,6 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; @@ -99,8 +98,8 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not messageEditText = new EditText(context); messageEditText.setHint(LocaleController.getString("AddCaption", R.string.AddCaption)); - messageEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); - messageEditText.setInputType(EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_CLASS_TEXT); + messageEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + messageEditText.setInputType(messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES); messageEditText.setMaxLines(4); messageEditText.setHorizontallyScrolling(false); messageEditText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); @@ -111,7 +110,7 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not messageEditText.setTextColor(0xffffffff); messageEditText.setHintTextColor(0xb2ffffff); InputFilter[] inputFilters = new InputFilter[1]; - inputFilters[0] = new InputFilter.LengthFilter(140); + inputFilters[0] = new InputFilter.LengthFilter(200); messageEditText.setFilters(inputFilters); frameLayout.addView(messageEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 52, 0, 6, 0)); messageEditText.setOnKeyListener(new OnKeyListener() { @@ -122,9 +121,6 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not showPopup(0); } return true; - } else if (i == KeyEvent.KEYCODE_ENTER && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { - delegate.onCaptionEnter(); - return true; } return false; } @@ -137,19 +133,20 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not } } }); - messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + /*messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { delegate.onCaptionEnter(); return true; - } else if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { + } else + if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { delegate.onCaptionEnter(); return true; } return false; } - }); + });*/ messageEditText.addTextChangedListener(new TextWatcher() { boolean processChange = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java index 71a23d079..d85fae84a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java @@ -99,7 +99,8 @@ public class PlayerView extends FrameLayout implements NotificationCenter.Notifi setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (fragment != null) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if (messageObject != null && messageObject.isMusic() && fragment != null) { fragment.presentFragment(new AudioPlayerActivity()); } } @@ -158,7 +159,7 @@ public class PlayerView extends FrameLayout implements NotificationCenter.Notifi create = true; } } - if (messageObject == null || !messageObject.isMusic()) { + if (messageObject == null || messageObject.getId() == 0/* || !messageObject.isMusic()*/) { lastMessageObject = null; if (visible) { visible = false; @@ -224,7 +225,14 @@ public class PlayerView extends FrameLayout implements NotificationCenter.Notifi } if (lastMessageObject != messageObject) { lastMessageObject = messageObject; - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s - %s", messageObject.getMusicAuthor(), messageObject.getMusicTitle())); + SpannableStringBuilder stringBuilder; + if (lastMessageObject.isVoice()) { + stringBuilder = new SpannableStringBuilder(String.format("%s %s", messageObject.getMusicAuthor(), messageObject.getMusicTitle())); + titleTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE); + } else { + stringBuilder = new SpannableStringBuilder(String.format("%s - %s", messageObject.getMusicAuthor(), messageObject.getMusicTitle())); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + } TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); stringBuilder.setSpan(span, 0, messageObject.getMusicAuthor().length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); titleTextView.setText(stringBuilder); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java index 7f6be1664..c68e8709b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java @@ -24,6 +24,7 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.FileLoader; import org.telegram.messenger.R; import org.telegram.messenger.MessageObject; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.Cells.BaseCell; import java.io.File; @@ -84,7 +85,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, TAG = MediaController.getInstance().generateObserverTag(); seekBar = new SeekBar(getContext()); - seekBar.delegate = this; + seekBar.setDelegate(this); progressView = new ProgressView(); } @@ -232,7 +233,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, boolean result = MediaController.getInstance().playAudio(currentMessageObject); if (!currentMessageObject.isOut() && currentMessageObject.isContentUnread()) { if (currentMessageObject.messageOwner.to_id.channel_id == 0) { - MessagesController.getInstance().markMessageContentAsRead(currentMessageObject.messageOwner); + MessagesController.getInstance().markMessageContentAsRead(currentMessageObject); currentMessageObject.setContentIsRead(); } } @@ -247,11 +248,11 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, invalidate(); } } else if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); buttonState = 3; invalidate(); } else if (buttonState == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.audio); + FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); buttonState = 2; invalidate(); } @@ -266,9 +267,15 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, seekBar.setProgress(currentMessageObject.audioProgress); } - int duration; + int duration = 0; if (!MediaController.getInstance().isPlayingAudio(currentMessageObject)) { - duration = currentMessageObject.messageOwner.media.audio.duration; + for (int a = 0; a < currentMessageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = currentMessageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } } else { duration = currentMessageObject.audioProgressSec; } @@ -282,7 +289,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, public void downloadAudioIfNeed() { if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); buttonState = 3; invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java index ed9293bf3..1dd5e1a50 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java @@ -85,6 +85,7 @@ public class RadioButton extends View { public void setColor(int color1, int color2) { color = color1; checkedColor = color2; + invalidate(); } private void cancelCheckAnimator() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java index 60bc74333..9777cdcc8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java @@ -9,11 +9,16 @@ package org.telegram.ui.Components; public class Rect { + public float x; public float y; public float width; public float height; + public Rect() { + + } + public Rect(float x, float y, float width, float height) { this.x = x; this.y = y; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java index 3effa8f94..5d705c37d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java @@ -39,9 +39,9 @@ public class ResourceLoader { public static Drawable[][] shareDrawable = new Drawable[2][2]; - public static Drawable viewsCountDrawable; + public static Drawable[] viewsCountDrawable = new Drawable[2]; public static Drawable viewsOutCountDrawable; - public static Drawable[] viewsMediaCountDrawable = new Drawable[2]; + public static Drawable viewsMediaCountDrawable; public static Drawable geoInDrawable; public static Drawable geoOutDrawable; @@ -79,10 +79,10 @@ public class ResourceLoader { backgroundBlack = context.getResources().getDrawable(R.drawable.system_black); backgroundBlue = context.getResources().getDrawable(R.drawable.system_blue); - viewsCountDrawable = context.getResources().getDrawable(R.drawable.post_views); + viewsCountDrawable[0] = context.getResources().getDrawable(R.drawable.post_views); + viewsCountDrawable[1] = context.getResources().getDrawable(R.drawable.post_views_s); viewsOutCountDrawable = context.getResources().getDrawable(R.drawable.post_viewsg); - viewsMediaCountDrawable[0] = context.getResources().getDrawable(R.drawable.post_views_w); - viewsMediaCountDrawable[1] = context.getResources().getDrawable(R.drawable.post_views_s); + viewsMediaCountDrawable = context.getResources().getDrawable(R.drawable.post_views_w); audioStatesDrawable[0][2] = audioStatesDrawable[0][0] = context.getResources().getDrawable(R.drawable.play_w2); audioStatesDrawable[0][1] = context.getResources().getDrawable(R.drawable.play_w2_pressed); 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 7e86e75c2..fddeafa74 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java @@ -33,7 +33,7 @@ public class SeekBar { private boolean pressed = false; public int width; public int height; - public SeekBarDelegate delegate; + private SeekBarDelegate delegate; public SeekBar(Context context) { if (innerPaint1 == null) { @@ -54,6 +54,10 @@ public class SeekBar { } } + public void setDelegate(SeekBarDelegate seekBarDelegate) { + delegate = seekBarDelegate; + } + public boolean onTouch(int action, float x, float y) { if (action == MotionEvent.ACTION_DOWN) { int additionWidth = (height - thumbWidth) / 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java new file mode 100644 index 000000000..385893d12 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java @@ -0,0 +1,190 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessageObject; + +public class SeekBarWaveform { + + private static Paint paintInner; + private static Paint paintOuter; + public int thumbX = 0; + public int thumbDX = 0; + private float startX; + private boolean startDraging = false; + private boolean pressed = false; + public int width; + public int height; + private SeekBar.SeekBarDelegate delegate; + private byte[] waveformBytes; + private MessageObject messageObject; + private View parentView; + private boolean selected; + + private int innerColor; + private int outerColor; + private int selectedColor; + + public SeekBarWaveform(Context context) { + if (paintInner == null) { + paintInner = new Paint(); + paintOuter = new Paint(); + } + } + + public void setDelegate(SeekBar.SeekBarDelegate seekBarDelegate) { + delegate = seekBarDelegate; + } + + public void setColors(int inner, int outer, int selected) { + innerColor = inner; + outerColor = outer; + selectedColor = selected; + } + + public void setWaveform(byte[] waveform) { + waveformBytes = waveform; + } + + public void setSelected(boolean value) { + selected = value; + } + + public void setMessageObject(MessageObject object) { + messageObject = object; + } + + public void setParentView(View view) { + parentView = view; + } + + public boolean isStartDraging() { + return startDraging; + } + + public boolean onTouch(int action, float x, float y) { + if (action == MotionEvent.ACTION_DOWN) { + if (0 <= x && x <= width && y >= 0 && y <= height) { + startX = x; + pressed = true; + thumbDX = (int) (x - thumbX); + startDraging = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (pressed) { + if (action == MotionEvent.ACTION_UP && delegate != null) { + delegate.onSeekBarDrag((float) thumbX / (float) width); + } + pressed = false; + return true; + } + } else if (action == MotionEvent.ACTION_MOVE) { + if (pressed) { + if (startDraging) { + thumbX = (int) (x - thumbDX); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > width) { + thumbX = width; + } + } + if (startX != -1 && Math.abs(x - startX) > AndroidUtilities.getPixelsInCM(0.2f, true)) { + if (parentView != null) { + parentView.getParent().requestDisallowInterceptTouchEvent(true); + } + startDraging = true; + startX = -1; + } + return true; + } + } + return false; + } + + public void setProgress(float progress) { + thumbX = (int)Math.ceil(width * progress); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > width) { + thumbX = width; + } + } + + public boolean isDragging() { + return pressed; + } + + public void draw(Canvas canvas) { + if (waveformBytes == null || width == 0) { + return; + } + float totalBarsCount = width / AndroidUtilities.dp(3); + if (totalBarsCount <= 0.1f) { + return; + } + byte value; + int samplesCount = (waveformBytes.length * 8 / 5); + float samplesPerBar = samplesCount / totalBarsCount; + float barCounter = 0; + int nextBarNum = 0; + + paintInner.setColor(messageObject != null && !messageObject.isOutOwner() && messageObject.isContentUnread() && messageObject.messageOwner.to_id.channel_id == 0 ? outerColor : (selected ? selectedColor : innerColor)); + paintOuter.setColor(outerColor); + + int y = (height - AndroidUtilities.dp(14)) / 2; + int barNum = 0; + int lastBarNum; + int drawBarCount; + + for (int a = 0; a < samplesCount; a++) { + if (a != nextBarNum) { + continue; + } + drawBarCount = 0; + lastBarNum = nextBarNum; + while (lastBarNum == nextBarNum) { + barCounter += samplesPerBar; + nextBarNum = (int) barCounter; + drawBarCount++; + } + + int bitPointer = a * 5; + int byteNum = bitPointer / 8; + int byteBitOffset = bitPointer - byteNum * 8; + int currentByteCount = 8 - byteBitOffset; + int nextByteRest = 5 - currentByteCount; + value = (byte) ((waveformBytes[byteNum] >> byteBitOffset) & ((2 << (Math.min(5, currentByteCount) - 1)) - 1)); + if (nextByteRest > 0) { + value <<= nextByteRest; + value |= waveformBytes[byteNum + 1] & ((2 << (nextByteRest - 1)) - 1); + } + + for (int b = 0; b < drawBarCount; b++) { + int x = barNum * AndroidUtilities.dp(3); + if (x < thumbX && x + AndroidUtilities.dp(2) < thumbX) { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), x + AndroidUtilities.dp(2), y + AndroidUtilities.dp(14), paintOuter); + } else { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), x + AndroidUtilities.dp(2), y + AndroidUtilities.dp(14), paintInner); + if (x < thumbX) { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), thumbX, y + AndroidUtilities.dp(14), paintOuter); + } + } + barNum++; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareFrameLayout.java index fa2291a6f..cad5ced81 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareFrameLayout.java @@ -9,6 +9,7 @@ package org.telegram.ui.Components; import android.content.Context; +import android.os.Build; import android.text.Editable; import android.text.InputType; import android.text.TextUtils; @@ -26,9 +27,11 @@ import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import android.widget.Toast; import org.telegram.SQLite.SQLiteCursor; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; @@ -37,7 +40,9 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; +import org.telegram.tgnet.ConnectionsManager; 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.BottomSheet; @@ -66,12 +71,44 @@ public class ShareFrameLayout extends FrameLayout { private EmptyTextProgressView searchEmptyView; private HashMap selectedDialogs = new HashMap<>(); - public ShareFrameLayout(Context context, BottomSheet bottomSheet, MessageObject messageObject) { + private TLRPC.TL_exportedMessageLink exportedMessageLink; + private boolean loadingLink; + private boolean copyLinkOnEnd; + + private boolean isPublicChannel; + + public ShareFrameLayout(final Context context, BottomSheet bottomSheet, final MessageObject messageObject, boolean publicChannel) { super(context); parentBottomSheet = bottomSheet; sendingMessageObject = messageObject; searchAdapter = new ShareSearchAdapter(context); + isPublicChannel = publicChannel; + + if (publicChannel) { + loadingLink = true; + TLRPC.TL_channels_exportMessageLink req = new TLRPC.TL_channels_exportMessageLink(); + req.id = messageObject.getId(); + req.channel = MessagesController.getInputChannel(messageObject.messageOwner.to_id.channel_id); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (response != null) { + exportedMessageLink = (TLRPC.TL_exportedMessageLink) response; + if (copyLinkOnEnd) { + copyLink(context); + } + } + loadingLink = false; + } + }); + + } + }); + } FrameLayout frameLayout = new FrameLayout(context); frameLayout.setBackgroundColor(0xffffffff); @@ -85,21 +122,31 @@ public class ShareFrameLayout extends FrameLayout { doneButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - ArrayList arrayList = new ArrayList<>(); - arrayList.add(sendingMessageObject); - for (HashMap.Entry entry : selectedDialogs.entrySet()) { - TLRPC.Dialog dialog = entry.getValue(); - boolean asAdmin = true; - int lower_id = (int) dialog.id; - if (lower_id < 0) { - TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); - if (chat.megagroup) { - asAdmin = false; - } + if (selectedDialogs.isEmpty() && isPublicChannel) { + if (loadingLink) { + copyLinkOnEnd = true; + Toast.makeText(ShareFrameLayout.this.getContext(), LocaleController.getString("Loading", R.string.Loading), Toast.LENGTH_SHORT).show(); + } else { + copyLink(ShareFrameLayout.this.getContext()); } - SendMessagesHelper.getInstance().sendMessage(arrayList, entry.getKey(), asAdmin); + parentBottomSheet.dismiss(); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(sendingMessageObject); + for (HashMap.Entry entry : selectedDialogs.entrySet()) { + TLRPC.Dialog dialog = entry.getValue(); + boolean asAdmin = true; + int lower_id = (int) dialog.id; + if (lower_id < 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (chat.megagroup) { + asAdmin = false; + } + } + SendMessagesHelper.getInstance().sendMessage(arrayList, entry.getKey(), asAdmin); + } + parentBottomSheet.dismiss(); } - parentBottomSheet.dismiss(); } }); @@ -118,7 +165,6 @@ public class ShareFrameLayout extends FrameLayout { doneButtonTextView.setTextColor(0xff19a7e8); doneButtonTextView.setGravity(Gravity.CENTER); doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); - doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); doneButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); @@ -218,7 +264,7 @@ public class ShareFrameLayout extends FrameLayout { selectedDialogs.put(dialog.id, dialog); cell.setChecked(true, true); } - updateSelectedCount(selectedDialogs.size(), true); + updateSelectedCount(); } }); @@ -229,20 +275,47 @@ public class ShareFrameLayout extends FrameLayout { gridView.setEmptyView(searchEmptyView); addView(searchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); - updateSelectedCount(selectedDialogs.size(), true); + updateSelectedCount(); } - public void updateSelectedCount(int count, boolean disable) { - if (count == 0) { + public void copyLink(Context context) { + if (exportedMessageLink == null) { + return; + } + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(exportedMessageLink.link); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", exportedMessageLink.link); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(context, LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void updateSelectedCount() { + if (selectedDialogs.isEmpty()) { doneButtonBadgeTextView.setVisibility(View.GONE); - doneButtonTextView.setTextColor(0xffb3b3b3); - doneButton.setEnabled(false); + if (!isPublicChannel) { + doneButtonTextView.setTextColor(0xffb3b3b3); + doneButton.setEnabled(false); + doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); + } else { + doneButtonTextView.setTextColor(0xff517fad); + doneButton.setEnabled(true); + doneButtonTextView.setText(LocaleController.getString("CopyLink", R.string.CopyLink).toUpperCase()); + } } else { doneButtonTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); doneButtonBadgeTextView.setVisibility(View.VISIBLE); - doneButtonBadgeTextView.setText(String.format("%d", count)); + doneButtonBadgeTextView.setText(String.format("%d", selectedDialogs.size())); doneButtonTextView.setTextColor(0xff3ec1f9); doneButton.setEnabled(true); + doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java index 421cb460c..97916e024 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -12,6 +12,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.database.DataSetObserver; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; @@ -22,6 +23,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.NotificationCenter; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Cells.StickerEmojiCell; +import org.telegram.ui.StickerPreviewViewer; import java.util.ArrayList; @@ -42,10 +44,22 @@ public class StickersAlert extends AlertDialog implements NotificationCenter.Not }; setView(container, AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); - gridView = new GridView(context); + gridView = new GridView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, gridView, 0); + return super.onInterceptTouchEvent(event) || result; + } + }; gridView.setNumColumns(4); gridView.setAdapter(new GridAdapter(context)); gridView.setVerticalScrollBarEnabled(false); + gridView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return StickerPreviewViewer.getInstance().onTouch(event, gridView, 0, null); + } + }); container.addView(gridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); setTitle(set.set.title); @@ -77,6 +91,10 @@ public class StickersAlert extends AlertDialog implements NotificationCenter.Not if (gridView != null) { gridView.invalidateViews(); } + if (StickerPreviewViewer.getInstance().isVisible()) { + StickerPreviewViewer.getInstance().close(); + } + StickerPreviewViewer.getInstance().reset(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java index 3153780c6..a9250c135 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java @@ -10,10 +10,7 @@ package org.telegram.ui.Components; import android.annotation.SuppressLint; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Build; -import android.provider.Browser; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -95,10 +92,7 @@ public class WebFrameLayout extends FrameLayout { textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - Uri uri = Uri.parse(openUrl); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName()); - getContext().startActivity(intent); + AndroidUtilities.openUrl(getContext(), openUrl); if (dialog != null) { dialog.dismiss(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 62f8777c1..15cd7859a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -39,6 +39,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; @@ -277,7 +278,11 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. } else { actionBar.setBackButtonDrawable(new MenuDrawable()); } - actionBar.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (BuildVars.DEBUG_VERSION) { + actionBar.setTitle(LocaleController.getString("AppNameBeta", R.string.AppNameBeta)); + } else { + actionBar.setTitle(LocaleController.getString("AppName", R.string.AppName)); + } } actionBar.setAllowOverlayTitle(true); @@ -849,7 +854,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter. ContactsController.getInstance().readContacts(); break; case Manifest.permission.WRITE_EXTERNAL_STORAGE: - ImageLoader.getInstance().createMediaPaths(); + ImageLoader.getInstance().checkMediaPaths(); break; } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 4a3fd98ab..5339c3d00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -9,6 +9,7 @@ package org.telegram.ui; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -77,12 +78,13 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private int beforeChangeIndex; private boolean ignoreChange; private CharSequence changeString; - private int maxCount = 199; + private int maxCount = 1000; private int chatType = ChatObject.CHAT_TYPE_CHAT; private boolean isAlwaysShare; private boolean isNeverShare; private boolean searchWas; private boolean searching; + private boolean isGroup; private HashMap selectedContacts = new HashMap<>(); private ArrayList allSpans = new ArrayList<>(); @@ -97,7 +99,8 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen chatType = args.getInt("chatType", ChatObject.CHAT_TYPE_CHAT); isAlwaysShare = args.getBoolean("isAlwaysShare", false); isNeverShare = args.getBoolean("isNeverShare", false); - maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? (MessagesController.getInstance().maxGroupCount - 1) : MessagesController.getInstance().maxBroadcastCount; + isGroup = args.getBoolean("isGroup", false); + maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? MessagesController.getInstance().maxMegagroupCount : MessagesController.getInstance().maxBroadcastCount; } @Override @@ -124,9 +127,17 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); if (isAlwaysShare) { - actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow)); + } else { + actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + } } else if (isNeverShare) { - actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("NeverAllow", R.string.NeverAllow)); + } else { + actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + } } else { actionBar.setTitle(chatType == ChatObject.CHAT_TYPE_CHAT ? LocaleController.getString("NewGroup", R.string.NewGroup) : LocaleController.getString("NewBroadcastList", R.string.NewBroadcastList)); actionBar.setSubtitle(LocaleController.formatString("MembersCount", R.string.MembersCount, selectedContacts.size(), maxCount)); @@ -191,9 +202,17 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen frameLayout.addView(userSelectEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 10, 0, 10, 0)); if (isAlwaysShare) { - userSelectEditText.setHint(LocaleController.getString("AlwaysShareWithPlaceholder", R.string.AlwaysShareWithPlaceholder)); + if (isGroup) { + userSelectEditText.setHint(LocaleController.getString("AlwaysAllowPlaceholder", R.string.AlwaysAllowPlaceholder)); + } else { + userSelectEditText.setHint(LocaleController.getString("AlwaysShareWithPlaceholder", R.string.AlwaysShareWithPlaceholder)); + } } else if (isNeverShare) { - userSelectEditText.setHint(LocaleController.getString("NeverShareWithPlaceholder", R.string.NeverShareWithPlaceholder)); + if (isGroup) { + userSelectEditText.setHint(LocaleController.getString("NeverAllowPlaceholder", R.string.NeverAllowPlaceholder)); + } else { + userSelectEditText.setHint(LocaleController.getString("NeverShareWithPlaceholder", R.string.NeverShareWithPlaceholder)); + } } else { userSelectEditText.setHint(LocaleController.getString("SendMessageTo", R.string.SendMessageTo)); } @@ -356,6 +375,14 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen if (maxCount != 0 && selectedContacts.size() == maxCount) { return; } + if (chatType == ChatObject.CHAT_TYPE_CHAT && selectedContacts.size() == MessagesController.getInstance().maxGroupCount - 1) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("SoftUserLimitAlert", R.string.SoftUserLimitAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + return; + } ignoreChange = true; ChipSpan span = createAndPutChipForUser(user); span.uid = user.id; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index 3cbe3a9e2..c2c220b7b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -164,7 +164,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati donePressed = true; if (chatType == ChatObject.CHAT_TYPE_BROADCAST) { - MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); } else { if (avatarUpdater.uploadingAvatar != null) { createAfterUpload = true; @@ -174,7 +174,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); - final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { @Override @@ -335,7 +335,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati avatarImage.setImage(avatar, "50_50", avatarDrawable); if (createAfterUpload) { FileLog.e("tmessages", "avatar did uploaded"); - MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); } } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java index 0dcbd1d6e..80409c3fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java @@ -10,28 +10,53 @@ package org.telegram.ui; import android.content.Context; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.util.TypedValue; +import android.view.Gravity; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.IdenticonDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.URLSpanReplacement; public class IdenticonActivity extends BaseFragment { + private int chat_id; + private static class LinkMovementMethodMy extends LinkMovementMethod { + @Override + public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { + try { + return super.onTouchEvent(widget, buffer, event); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + } + public IdenticonActivity(Bundle args) { super(args); } @@ -57,18 +82,11 @@ public class IdenticonActivity extends BaseFragment { } }); - fragmentView = getParentActivity().getLayoutInflater().inflate(R.layout.identicon_layout, null, false); - ImageView identiconView = (ImageView) fragmentView.findViewById(R.id.identicon_view); - TextView textView = (TextView) fragmentView.findViewById(R.id.identicon_text); - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(chat_id); - if (encryptedChat != null) { - IdenticonDrawable drawable = new IdenticonDrawable(); - identiconView.setImageDrawable(drawable); - drawable.setEncryptedChat(encryptedChat); - TLRPC.User user = MessagesController.getInstance().getUser(encryptedChat.user_id); - textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("EncryptionKeyDescription", R.string.EncryptionKeyDescription, user.first_name, user.first_name))); - } - + fragmentView = new LinearLayout(context); + LinearLayout linearLayout = (LinearLayout) fragmentView; + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.setWeightSum(100); + linearLayout.setBackgroundColor(0xfff0f0f0); fragmentView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { @@ -76,6 +94,61 @@ public class IdenticonActivity extends BaseFragment { } }); + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(20), AndroidUtilities.dp(20), AndroidUtilities.dp(20)); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 50.0f)); + + ImageView identiconView = new ImageView(context); + identiconView.setScaleType(ImageView.ScaleType.FIT_XY); + frameLayout.addView(identiconView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(0xffffffff); + frameLayout.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), AndroidUtilities.dp(10)); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 50.0f)); + + TextView textView = new TextView(context); + textView.setTextColor(0xff7f7f7f); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLinksClickable(true); + textView.setClickable(true); + textView.setMovementMethod(new LinkMovementMethodMy()); + //textView.setAutoLinkMask(Linkify.WEB_URLS); + textView.setLinkTextColor(0xff316f9f); + textView.setGravity(Gravity.CENTER); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(chat_id); + if (encryptedChat != null) { + IdenticonDrawable drawable = new IdenticonDrawable(); + identiconView.setImageDrawable(drawable); + drawable.setEncryptedChat(encryptedChat); + TLRPC.User user = MessagesController.getInstance().getUser(encryptedChat.user_id); + SpannableStringBuilder hash = new SpannableStringBuilder(); + if (encryptedChat.key_hash.length > 16) { + String hex = Utilities.bytesToHex(encryptedChat.key_hash); + for (int a = 0; a < 32; a++) { + if (a != 0) { + if (a % 8 == 0) { + hash.append('\n'); + } else if (a % 4 == 0) { + hash.append(' '); + } + } + hash.append(hex.substring(a * 2, a * 2 + 2)); + hash.append(' '); + } + hash.append("\n\n"); + } + hash.append(AndroidUtilities.replaceTags(LocaleController.formatString("EncryptionKeyDescription", R.string.EncryptionKeyDescription, user.first_name, user.first_name))); + final String url = "telegram.org"; + int index = hash.toString().indexOf(url); + if (index != -1) { + hash.setSpan(new URLSpanReplacement(LocaleController.getString("EncryptionKeyLink", R.string.EncryptionKeyLink)), index, index + url.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + textView.setText(hash); + } + return fragmentView; } @@ -100,7 +173,7 @@ public class IdenticonActivity extends BaseFragment { return true; } fragmentView.getViewTreeObserver().removeOnPreDrawListener(this); - LinearLayout layout = (LinearLayout)fragmentView; + LinearLayout layout = (LinearLayout) fragmentView; WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java index aa7f88506..006bc6b22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java @@ -28,7 +28,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.tgnet.ConnectionsManager; @@ -221,7 +221,7 @@ public class IntroActivity extends Activity { finish(); } }); - if (BuildConfig.DEBUG) { + if (BuildVars.DEBUG_VERSION) { startMessagingButton.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index cf8005f79..213d5155a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -24,7 +24,6 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; -import android.provider.Browser; import android.provider.ContactsContract; import android.support.annotation.NonNull; import android.view.ActionMode; @@ -53,6 +52,7 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NativeCrashManager; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; import org.telegram.messenger.query.StickersQuery; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; @@ -75,6 +75,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.List; import java.util.Map; public class LaunchActivity extends Activity implements ActionBarLayout.ActionBarLayoutDelegate, NotificationCenter.NotificationCenterDelegate, DialogsActivity.MessagesActivityDelegate { @@ -327,12 +328,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa presentFragment(new SettingsActivity()); drawerLayoutContainer.closeDrawer(false); } else if (position == 9) { - try { - Intent pickIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))); - startActivityForResult(pickIntent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + AndroidUtilities.openUrl(LaunchActivity.this, LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); drawerLayoutContainer.closeDrawer(false); } } @@ -610,7 +606,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa error = true; } } else { - if (type != null && (type.equals("text/plain") || type.equals("message/rfc822")) && (intent.getStringExtra(Intent.EXTRA_TEXT) != null || intent.getCharSequenceExtra(Intent.EXTRA_TEXT) != null)) { + if ((type == null || type != null && (type.equals("text/plain") || type.equals("message/rfc822"))) && (intent.getStringExtra(Intent.EXTRA_TEXT) != null || intent.getCharSequenceExtra(Intent.EXTRA_TEXT) != null)) { String text = intent.getStringExtra(Intent.EXTRA_TEXT); if (text == null) { text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT).toString(); @@ -622,8 +618,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa text = subject + "\n" + text; } sendingText = text; - } else { - error = true; + } else if (subject != null && subject.length() > 0) { + sendingText = subject; } } Parcelable parcelable = intent.getParcelableExtra(Intent.EXTRA_STREAM); @@ -633,38 +629,48 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa parcelable = Uri.parse(parcelable.toString()); } Uri uri = (Uri) parcelable; - if (uri != null && (type != null && type.startsWith("image/") || uri.toString().toLowerCase().endsWith(".jpg"))) { - if (photoPathsArray == null) { - photoPathsArray = new ArrayList<>(); - } - photoPathsArray.add(uri); - } else { - path = AndroidUtilities.getPath(uri); - if (path != null) { - if (path.startsWith("file:")) { - path = path.replace("file://", ""); + if (uri != null) { + if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { + String pathString = Utilities.readlink(uri.getPath()); + if (pathString != null && pathString.contains("/data/data/" + getPackageName() + "/files")) { + error = true; } - if (type != null && type.startsWith("video/")) { - videoPath = path; - } else { - if (documentsPathsArray == null) { - documentsPathsArray = new ArrayList<>(); - documentsOriginalPathsArray = new ArrayList<>(); - } - documentsPathsArray.add(path); - documentsOriginalPathsArray.add(uri.toString()); - } - } else { - if (documentsUrisArray == null) { - documentsUrisArray = new ArrayList<>(); - } - documentsUrisArray.add(uri); - documentsMimeType = type; } } - if (sendingText != null) { - if (sendingText.contains("WhatsApp")) { //remove unnecessary caption 'sent from WhatsApp' from photos forwarded from WhatsApp - sendingText = null; + if (!error) { + if (uri != null && (type != null && type.startsWith("image/") || uri.toString().toLowerCase().endsWith(".jpg"))) { + if (photoPathsArray == null) { + photoPathsArray = new ArrayList<>(); + } + photoPathsArray.add(uri); + } else { + path = AndroidUtilities.getPath(uri); + if (path != null) { + if (path.startsWith("file:")) { + path = path.replace("file://", ""); + } + if (type != null && type.startsWith("video/")) { + videoPath = path; + } else { + if (documentsPathsArray == null) { + documentsPathsArray = new ArrayList<>(); + documentsOriginalPathsArray = new ArrayList<>(); + } + documentsPathsArray.add(path); + documentsOriginalPathsArray.add(uri.toString()); + } + } else { + if (documentsUrisArray == null) { + documentsUrisArray = new ArrayList<>(); + } + documentsUrisArray.add(uri); + documentsMimeType = type; + } + } + if (sendingText != null) { + if (sendingText.contains("WhatsApp")) { //remove unnecessary caption 'sent from WhatsApp' from photos forwarded from WhatsApp + sendingText = null; + } } } } else if (sendingText == null) { @@ -679,9 +685,31 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa try { ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); String type = intent.getType(); + if (uris != null) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); + if (!(parcelable instanceof Uri)) { + parcelable = Uri.parse(parcelable.toString()); + } + Uri uri = (Uri) parcelable; + if (uri != null) { + if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { + String pathString = Utilities.readlink(uri.getPath()); + if (pathString != null && pathString.contains("/data/data/" + getPackageName() + "/files")) { + uris.remove(a); + a--; + } + } + } + } + if (uris.isEmpty()) { + uris = null; + } + } if (uris != null) { if (type != null && type.startsWith("image/")) { - for (Parcelable parcelable : uris) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); if (!(parcelable instanceof Uri)) { parcelable = Uri.parse(parcelable.toString()); } @@ -692,7 +720,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa photoPathsArray.add(uri); } } else { - for (Parcelable parcelable : uris) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); if (!(parcelable instanceof Uri)) { parcelable = Uri.parse(parcelable.toString()); } @@ -733,6 +762,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa String botUser = null; String botChat = null; String message = null; + Integer messageId = null; boolean hasUrl = false; String scheme = data.getScheme(); if (scheme != null) { @@ -758,8 +788,17 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } message += data.getQueryParameter("text"); } - } else if (path.length() >= 3) { - username = data.getLastPathSegment(); + } else if (path.length() >= 1) { + List segments = data.getPathSegments(); + if (segments.size() > 0) { + username = segments.get(0); + if (segments.size() > 1) { + messageId = Utilities.parseInt(segments.get(1)); + if (messageId == 0) { + messageId = null; + } + } + } botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); } @@ -799,7 +838,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } if (username != null || group != null || sticker != null || message != null) { - runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, 0); + runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, messageId, 0); } else { try { Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null); @@ -986,7 +1025,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa return false; } - private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final boolean hasUrl, final int state) { + private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final boolean hasUrl, final Integer messageId, final int state) { final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); progressDialog.setCanceledOnTouchOutside(false); @@ -1051,6 +1090,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (botUser != null && res.users.size() > 0 && res.users.get(0).bot) { args.putString("botUser", botUser); } + if (messageId != null) { + args.putInt("message_id", messageId); + } ChatActivity fragment = new ChatActivity(args); NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); actionBarLayout.presentFragment(fragment, false, true, true); @@ -1106,7 +1148,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, 1); + runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, messageId, 1); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -1494,7 +1536,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (requestCode == 3 || requestCode == 4 || requestCode == 5) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (requestCode == 4) { - ImageLoader.getInstance().createMediaPaths(); + ImageLoader.getInstance().checkMediaPaths(); } else if (requestCode == 5) { ContactsController.getInstance().readContacts(); } @@ -1678,13 +1720,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("NobodyLikesSpamUrl", R.string.NobodyLikesSpamUrl))); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName()); - startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + AndroidUtilities.openUrl(LaunchActivity.this, LocaleController.getString("NobodyLikesSpamUrl", R.string.NobodyLikesSpamUrl)); } }); } @@ -1882,7 +1918,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { + if (keyCode == KeyEvent.KEYCODE_MENU && !UserConfig.isWaitingForPasscodeEnter) { if (AndroidUtilities.isTablet()) { if (layersActionBarLayout.getVisibility() == View.VISIBLE && !layersActionBarLayout.fragmentsStack.isEmpty()) { layersActionBarLayout.onKeyUp(keyCode, event); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index e4e016a42..51e5088b2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -817,10 +817,10 @@ public class LocationActivity extends BaseFragment implements NotificationCenter if (messageObject != null && avatarImageView != null) { int fromId = messageObject.messageOwner.from_id; if (messageObject.isForwarded()) { - if (messageObject.messageOwner.fwd_from_id.user_id != 0) { - fromId = messageObject.messageOwner.fwd_from_id.user_id; + if (messageObject.messageOwner.fwd_from.channel_id != 0) { + fromId = -messageObject.messageOwner.fwd_from.channel_id; } else { - fromId = -messageObject.messageOwner.fwd_from_id.channel_id; + fromId = messageObject.messageOwner.fwd_from.from_id; } } String name = ""; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index 74f5c95fb..358bc1127 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -400,7 +400,7 @@ public class LoginActivity extends BaseFragment { NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); } - public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener { + public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener, NotificationCenter.NotificationCenterDelegate { private EditText codeField; private HintEditText phoneField; @@ -752,6 +752,17 @@ public class LoginActivity extends BaseFragment { } } + @Override + public void didReceivedNotification(int id, final Object... args) { + /*if (id == NotificationCenter.didReceiveCall) { + if (codeField != null) { + String phone = (String) args[0]; + phone = PhoneFormat.stripExceptNumbers(phone); + codeField.setText(phone); + } + }*/ + } + @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { if (ignoreSelection) { @@ -785,6 +796,7 @@ public class LoginActivity extends BaseFragment { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); return; } + //NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); ConnectionsManager.getInstance().cleanUp(); TLRPC.TL_auth_sendCode req = new TLRPC.TL_auth_sendCode(); @@ -857,6 +869,7 @@ public class LoginActivity extends BaseFragment { codeField.requestFocus(); } } + //NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveCall); } @Override @@ -1071,9 +1084,14 @@ public class LoginActivity extends BaseFragment { destroyTimer(); destroyCodeTimer(); - timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); - lastCurrentTime = System.currentTimeMillis(); - problemText.setVisibility(time < 1000 ? VISIBLE : GONE); + if (time >= 3600 * 1000) { + timeText.setVisibility(GONE); + problemText.setVisibility(GONE); + } else { + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); + lastCurrentTime = System.currentTimeMillis(); + problemText.setVisibility(time < 1000 ? VISIBLE : GONE); + } createTimer(); } @@ -1119,7 +1137,7 @@ public class LoginActivity extends BaseFragment { } private void createTimer() { - if (timeTimer != null) { + if (timeTimer != null || time >= 3600 * 1000) { return; } timeTimer = new Timer(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index 5ee1c3916..e3d856b3f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -18,7 +18,6 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.provider.Browser; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -446,6 +445,11 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No if ((int) dialog_id != 0) { dropDownContainer.addSubItem(links_item, LocaleController.getString("LinksTitle", R.string.LinksTitle), 0); dropDownContainer.addSubItem(music_item, LocaleController.getString("AudioTitle", R.string.AudioTitle), 0); + } else { + TLRPC.EncryptedChat currentEncryptedChat = MessagesController.getInstance().getEncryptedChat((int) (dialog_id >> 32)); + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46) { + dropDownContainer.addSubItem(music_item, LocaleController.getString("AudioTitle", R.string.AudioTitle), 0); + } } actionBar.addView(dropDownContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 64 : 56, 0, 40, 0)); dropDownContainer.setOnClickListener(new View.OnClickListener() { @@ -1115,10 +1119,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No link = ((SharedLinkCell) view).getLink(0); } if (link != null) { - Uri uri = Uri.parse(link); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getParentActivity().getPackageName()); - getParentActivity().startActivity(intent); + AndroidUtilities.openUrl(getParentActivity(), link); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1541,7 +1542,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } else if (currentType == 3) { req.filter = new TLRPC.TL_inputMessagesFilterUrl(); } else if (currentType == 4) { - req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments(); + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); } req.q = query; req.peer = MessagesController.getInputPeer(uid); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index fa07e8ffb..50e819baf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -28,7 +28,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.provider.Browser; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.TypedValue; import android.view.GestureDetector; @@ -48,6 +48,7 @@ import android.widget.Scroller; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.UserObject; @@ -180,19 +181,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean draggingDown = false; private float dragY; - private float translationX = 0; - private float translationY = 0; + private float translationX; + private float translationY; private float scale = 1; private float animateToX; private float animateToY; private float animateToScale; private float animationValue; + private int currentRotation; private long animationStartTime; private AnimatorSetProxy imageMoveAnimation; private AnimatorSetProxy changeModeAnimation; private GestureDetector gestureDetector; private DecelerateInterpolator interpolator = new DecelerateInterpolator(1.5f); - private float pinchStartDistance = 0; + private float pinchStartDistance; private float pinchStartScale = 1; private float pinchCenterX; private float pinchCenterY; @@ -960,7 +962,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (f != null && f.exists()) { - MediaController.saveFile(f.toString(), parentActivity, currentFileNames[0].endsWith("mp4") ? 1 : 0, null); + MediaController.saveFile(f.toString(), parentActivity, currentMessageObject != null && currentMessageObject.isVideo() ? 1 : 0, null); } else { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); @@ -1020,7 +1022,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); - if (currentFileNames[0] != null && currentFileNames[0].endsWith("mp4")) { + if (currentMessageObject != null && currentMessageObject.isVideo()) { builder.setMessage(LocaleController.formatString("AreYouSureDeleteVideo", R.string.AreYouSureDeleteVideo)); } else { builder.setMessage(LocaleController.formatString("AreYouSureDeletePhoto", R.string.AreYouSureDeletePhoto)); @@ -1200,13 +1202,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } try { File f = null; + boolean isVideo = false; if (currentMessageObject != null) { + isVideo = currentMessageObject.isVideo(); if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - Uri uri = Uri.parse(currentMessageObject.messageOwner.media.webpage.url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, parentActivity.getPackageName()); - parentActivity.startActivity(intent); + AndroidUtilities.openUrl(parentActivity, currentMessageObject.messageOwner.media.webpage.url); return; } f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); @@ -1216,7 +1217,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); - if (f.toString().endsWith("mp4")) { + if (isVideo) { intent.setType("video/mp4"); } else { intent.setType("image/jpeg"); @@ -1306,6 +1307,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); + ImageView rotateButton = new ImageView(parentActivity); + rotateButton.setScaleType(ImageView.ScaleType.CENTER); + rotateButton.setImageResource(R.drawable.tool_rotate); + rotateButton.setBackgroundResource(R.drawable.bar_selector_white); + editorDoneLayout.addView(rotateButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER)); + rotateButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + centerImage.setOrientation(centerImage.getOrientation() - 90, false); + photoCropView.setOrientation(centerImage.getOrientation()); + containerView.invalidate(); + } + }); + gestureDetector = new GestureDetector(containerView.getContext(), this); gestureDetector.setOnDoubleTapListener(this); @@ -2074,23 +2089,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return null; } if (!imagesArrLocations.isEmpty() || !imagesArr.isEmpty()) { - TLRPC.InputFileLocation file = getInputFileLocation(index); - if (file == null) { - return null; - } if (!imagesArrLocations.isEmpty()) { - return file.volume_id + "_" + file.local_id + ".jpg"; - } else if (!imagesArr.isEmpty()) { - MessageObject message = imagesArr.get(index); - if (message.messageOwner instanceof TLRPC.TL_messageService) { - return file.volume_id + "_" + file.local_id + ".jpg"; - } else if (message.messageOwner.media != null) { - if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - return file.volume_id + "_" + file.id + ".mp4"; - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - return file.volume_id + "_" + file.local_id + ".jpg"; - } + if (index >= imagesArrLocations.size()) { + return null; } + TLRPC.FileLocation location = imagesArrLocations.get(index); + return location.volume_id + "_" + location.local_id + ".jpg"; + } else if (!imagesArr.isEmpty()) { + if (index >= imagesArr.size()) { + return null; + } + return FileLoader.getMessageFileName(imagesArr.get(index).messageOwner); } } else if (!imagesArrLocals.isEmpty()) { if (index >= imagesArrLocals.size()) { @@ -2109,7 +2118,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat searchImage.localUrl = ""; } } - return Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl); + return Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); } } return null; @@ -2156,72 +2165,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { size[0] = -1; } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo && message.messageOwner.media.video != null && message.messageOwner.media.video.thumb != null) { - size[0] = message.messageOwner.media.video.thumb.size; + } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaDocument && message.messageOwner.media.document != null && message.messageOwner.media.document.thumb != null) { + size[0] = message.messageOwner.media.document.thumb.size; if (size[0] == 0) { size[0] = -1; } - return message.messageOwner.media.video.thumb.location; - } - } - return null; - } - - private TLRPC.InputFileLocation getInputFileLocation(int index) { - if (index < 0) { - return null; - } - if (!imagesArrLocations.isEmpty()) { - if (index >= imagesArrLocations.size()) { - return null; - } - TLRPC.FileLocation sizeFull = imagesArrLocations.get(index); - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.local_id; - location.volume_id = sizeFull.volume_id; - location.id = sizeFull.dc_id; - location.secret = sizeFull.secret; - return location; - } else if (!imagesArr.isEmpty()) { - if (index >= imagesArr.size()) { - return null; - } - MessageObject message = imagesArr.get(index); - if (message.messageOwner instanceof TLRPC.TL_messageService) { - if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { - TLRPC.FileLocation sizeFull = message.messageOwner.action.newUserPhoto.photo_big; - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.local_id; - location.volume_id = sizeFull.volume_id; - location.id = sizeFull.dc_id; - location.secret = sizeFull.secret; - return location; - } else { - TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (sizeFull != null) { - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.location.local_id; - location.volume_id = sizeFull.location.volume_id; - location.id = sizeFull.location.dc_id; - location.secret = sizeFull.location.secret; - return location; - } - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (sizeFull != null) { - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.location.local_id; - location.volume_id = sizeFull.location.volume_id; - location.id = sizeFull.location.dc_id; - location.secret = sizeFull.location.secret; - return location; - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - TLRPC.TL_inputVideoFileLocation location = new TLRPC.TL_inputVideoFileLocation(); - location.volume_id = message.messageOwner.media.video.dc_id; - location.id = message.messageOwner.media.video.id; - return location; + return message.messageOwner.media.document.thumb.location; } } return null; @@ -2353,7 +2302,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canShowBottom = false; Object obj = imagesArrLocals.get(index); cropItem.setVisibility(obj instanceof MediaController.PhotoEntry || obj instanceof MediaController.SearchImage && ((MediaController.SearchImage) obj).type == 0 ? View.VISIBLE : View.GONE); - if (parentChatActivity != null && parentChatActivity.currentEncryptedChat == null) { + if (parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 46)) { mentionsAdapter.setChatInfo(parentChatActivity.info); mentionsAdapter.setNeedUsernames(parentChatActivity.currentChat != null); mentionsAdapter.setNeedBotContext(false); @@ -2401,7 +2350,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat placeProvider.willSwitchFromPhoto(currentMessageObject, currentFileLocation, currentIndex); int prevIndex = currentIndex; currentIndex = index; - + boolean isVideo = false; boolean sameImage = false; if (!imagesArr.isEmpty()) { @@ -2410,12 +2359,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } currentMessageObject = imagesArr.get(currentIndex); + isVideo = currentMessageObject.isVideo(); if (currentMessageObject.canDeleteMessage(null)) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } - if (currentMessageObject.messageOwner.from_id > 0) { + if (currentMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); if (user != null) { nameTextView.setText(UserObject.getUserName(user)); @@ -2423,7 +2373,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat nameTextView.setText(""); } } else { - TLRPC.Chat chat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); + TLRPC.Chat chat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); if (chat != null) { nameTextView.setText(chat.title); } else { @@ -2432,8 +2382,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } long date = (long) currentMessageObject.messageOwner.date * 1000; String dateString = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))); - if (currentFileNames[0] != null && currentFileNames[0].endsWith("mp4")) { - dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(currentMessageObject.messageOwner.media.video.size))); + if (currentFileNames[0] != null && isVideo) { + dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(currentMessageObject.messageOwner.media.document.size))); } else { dateTextView.setText(dateString); } @@ -2580,7 +2530,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canDragDown = true; changingPage = false; switchImageAfterAnimation = 0; - canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0); + canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); updateMinMax(scale); } @@ -2629,8 +2579,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat captionTextViewNew = captionTextView; captionItem.setIcon(R.drawable.photo_text2); - captionTextView.setTag(caption); - captionTextView.setText(caption); + CharSequence str = Emoji.replaceEmoji(new SpannableStringBuilder(caption.toString()), MessageObject.textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + captionTextView.setTag(str); + captionTextView.setText(str); ViewProxy.setAlpha(captionTextView, bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? 1.0f : 0.0f); AndroidUtilities.runOnUIThread(new Runnable() { @Override @@ -2658,9 +2609,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat index -= 1; } File f = null; + boolean isVideo = false; if (currentMessageObject != null) { MessageObject messageObject = imagesArr.get(index); f = FileLoader.getPathToMessage(messageObject.messageOwner); + isVideo = messageObject.isVideo(); } else if (currentFileLocation != null) { TLRPC.FileLocation location = imagesArrLocations.get(index); f = FileLoader.getPathToAttach(location, avatarsUserId != 0); @@ -2671,13 +2624,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } if (f != null && f.exists()) { - if (currentPathObject == null && currentFileNames[a].endsWith("mp4")) { + if (isVideo) { radialProgressViews[a].setBackgroundState(3, animated); } else { radialProgressViews[a].setBackgroundState(-1, animated); } } else { - if (currentPathObject == null && currentFileNames[a].endsWith("mp4")) { + if (isVideo) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) { radialProgressViews[a].setBackgroundState(2, false); } else { @@ -2693,7 +2646,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat radialProgressViews[a].setProgress(progress, false); } if (a == 0) { - canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0); + canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); } } else { radialProgressViews[a].setBackgroundState(-1, animated); @@ -2762,9 +2715,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageReceiver.setShouldGenerateQualityThumb(true); } - if (messageObject != null && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + if (messageObject != null && messageObject.isVideo()) { imageReceiver.setNeedsQualityThumb(true); - if (messageObject.messageOwner.media.video.thumb != null) { + if (messageObject.photoThumbs != null && !messageObject.photoThumbs.isEmpty()) { Bitmap placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; @@ -3963,9 +3916,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (loadFile) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true); + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, true, false); } else { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video); + FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index 2125e4d5d..e63a43f7e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -308,6 +308,11 @@ public class PopupNotificationActivity extends Activity implements NotificationC } + @Override + public void onMessageEditEnd() { + + } + @Override public void needSendTyping() { if (currentMessageObject != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java similarity index 79% rename from TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java rename to TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index c1d165a14..79377a656 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -43,14 +43,14 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.HeaderCell; -import org.telegram.ui.Cells.LastSeenRadioCell; +import org.telegram.ui.Cells.RadioCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; -public class LastSeenActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { +public class PrivacyControlActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListAdapter listAdapter; private View doneButton; @@ -60,11 +60,15 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private ArrayList currentMinus; private int lastCheckedType = -1; - private int lastSeenSectionRow; + private boolean isGroup; + + private boolean enableAnimation; + + private int sectionRow; private int everybodyRow; private int myContactsRow; private int nobodyRow; - private int lastSeenDetailRow; + private int detailRow; private int shareSectionRow; private int alwaysShareRow; private int neverShareRow; @@ -85,6 +89,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } } + public PrivacyControlActivity(boolean group) { + super(); + isGroup = group; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -104,7 +113,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels)); + } else { + actionBar.setTitle(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen)); + } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -115,12 +128,16 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter return; } - if (currentType != 0) { + if (currentType != 0 && !isGroup) { final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); boolean showed = preferences.getBoolean("privacyAlertShowed", false); if (!showed) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + if (isGroup) { + builder.setMessage(LocaleController.getString("WhoCanAddMeInfo", R.string.WhoCanAddMeInfo)); + } else { + builder.setMessage(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override @@ -176,6 +193,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter if (newType == currentType) { return; } + enableAnimation = true; doneButton.setVisibility(View.VISIBLE); lastCheckedType = currentType; currentType = newType; @@ -190,19 +208,20 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter if (createFromArray.isEmpty()) { Bundle args = new Bundle(); args.putBoolean(i == neverShareRow ? "isNeverShare" : "isAlwaysShare", true); + args.putBoolean("isGroup", isGroup); GroupCreateActivity fragment = new GroupCreateActivity(args); fragment.setDelegate(new GroupCreateActivity.GroupCreateActivityDelegate() { @Override public void didSelectUsers(ArrayList ids) { if (i == neverShareRow) { currentMinus = ids; - for (Integer id : currentMinus) { - currentPlus.remove(id); + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); } } else { currentPlus = ids; - for (Integer id : currentPlus) { - currentMinus.remove(id); + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); } } doneButton.setVisibility(View.VISIBLE); @@ -212,22 +231,22 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter }); presentFragment(fragment); } else { - LastSeenUsersActivity fragment = new LastSeenUsersActivity(createFromArray, i == alwaysShareRow); - fragment.setDelegate(new LastSeenUsersActivity.LastSeenUsersActivityDelegate() { + PrivacyUsersActivity fragment = new PrivacyUsersActivity(createFromArray, isGroup, i == alwaysShareRow); + fragment.setDelegate(new PrivacyUsersActivity.PrivacyActivityDelegate() { @Override public void didUpdatedUserList(ArrayList ids, boolean added) { if (i == neverShareRow) { currentMinus = ids; if (added) { - for (Integer id : currentMinus) { - currentPlus.remove(id); + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); } } } else { currentPlus = ids; if (added) { - for (Integer id : currentPlus) { - currentMinus.remove(id); + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); } } } @@ -253,11 +272,15 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void applyCurrentPrivacySettings() { TLRPC.TL_account_setPrivacy req = new TLRPC.TL_account_setPrivacy(); - req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + if (isGroup) { + req.key = new TLRPC.TL_inputPrivacyKeyChatInvite(); + } else { + req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + } if (currentType != 0 && currentPlus.size() > 0) { TLRPC.TL_inputPrivacyValueAllowUsers rule = new TLRPC.TL_inputPrivacyValueAllowUsers(); - for (Integer uid : currentPlus) { - TLRPC.User user = MessagesController.getInstance().getUser(uid); + for (int a = 0; a < currentPlus.size(); a++) { + TLRPC.User user = MessagesController.getInstance().getUser(currentPlus.get(a)); if (user != null) { TLRPC.InputUser inputUser = MessagesController.getInputUser(user); if (inputUser != null) { @@ -269,8 +292,8 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } if (currentType != 1 && currentMinus.size() > 0) { TLRPC.TL_inputPrivacyValueDisallowUsers rule = new TLRPC.TL_inputPrivacyValueDisallowUsers(); - for (Integer uid : currentMinus) { - TLRPC.User user = MessagesController.getInstance().getUser(uid); + for (int a = 0; a < currentMinus.size(); a++) { + TLRPC.User user = MessagesController.getInstance().getUser(currentMinus.get(a)); if (user != null) { TLRPC.InputUser inputUser = MessagesController.getInputUser(user); if (inputUser != null) { @@ -313,7 +336,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter finishFragment(); TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; MessagesController.getInstance().putUsers(rules.users, false); - ContactsController.getInstance().setPrivacyRules(rules.rules); + ContactsController.getInstance().setPrivacyRules(rules.rules, isGroup); } else { showErrorAlert(); } @@ -337,13 +360,14 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void checkPrivacy() { currentPlus = new ArrayList<>(); currentMinus = new ArrayList<>(); - ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(); + ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(isGroup); if (privacyRules.size() == 0) { currentType = 1; return; } int type = -1; - for (TLRPC.PrivacyRule rule : privacyRules) { + for (int a = 0; a < privacyRules.size(); a++) { + TLRPC.PrivacyRule rule = privacyRules.get(a); if (rule instanceof TLRPC.TL_privacyValueAllowUsers) { currentPlus.addAll(rule.users); } else if (rule instanceof TLRPC.TL_privacyValueDisallowUsers) { @@ -371,11 +395,15 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void updateRows() { rowCount = 0; - lastSeenSectionRow = rowCount++; + sectionRow = rowCount++; everybodyRow = rowCount++; myContactsRow = rowCount++; - nobodyRow = rowCount++; - lastSeenDetailRow = rowCount++; + if (isGroup) { + nobodyRow = -1; + } else { + nobodyRow = rowCount++; + } + detailRow = rowCount++; shareSectionRow = rowCount++; if (currentType == 1 || currentType == 2) { alwaysShareRow = rowCount++; @@ -397,9 +425,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public void onResume() { super.onResume(); lastCheckedType = -1; - if (listAdapter != null) { - listAdapter.notifyDataSetChanged(); - } + enableAnimation = false; } private class ListAdapter extends BaseFragmentAdapter { @@ -455,7 +481,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } else { value = LocaleController.getString("EmpryUsersPlaceholder", R.string.EmpryUsersPlaceholder); } - textCell.setTextAndValue(LocaleController.getString("AlwaysShareWith", R.string.AlwaysShareWith), value, neverShareRow != -1); + if (isGroup) { + textCell.setTextAndValue(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow), value, neverShareRow != -1); + } else { + textCell.setTextAndValue(LocaleController.getString("AlwaysShareWith", R.string.AlwaysShareWith), value, neverShareRow != -1); + } } else if (i == neverShareRow) { String value; if (currentMinus.size() != 0) { @@ -463,18 +493,30 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } else { value = LocaleController.getString("EmpryUsersPlaceholder", R.string.EmpryUsersPlaceholder); } - textCell.setTextAndValue(LocaleController.getString("NeverShareWith", R.string.NeverShareWith), value, false); + if (isGroup) { + textCell.setTextAndValue(LocaleController.getString("NeverAllow", R.string.NeverAllow), value, false); + } else { + textCell.setTextAndValue(LocaleController.getString("NeverShareWith", R.string.NeverShareWith), value, false); + } } } else if (type == 1) { if (view == null) { view = new TextInfoPrivacyCell(mContext); view.setBackgroundColor(0xffffffff); } - if (i == lastSeenDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + if (i == detailRow) { + if (isGroup) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("WhoCanAddMeInfo", R.string.WhoCanAddMeInfo)); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + } view.setBackgroundResource(R.drawable.greydivider); } else if (i == shareDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareSettingsHelp", R.string.CustomShareSettingsHelp)); + if (isGroup) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareInfo", R.string.CustomShareInfo)); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareSettingsHelp", R.string.CustomShareSettingsHelp)); + } view.setBackgroundResource(R.drawable.greydivider_bottom); } } else if (type == 2) { @@ -482,32 +524,36 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter view = new HeaderCell(mContext); view.setBackgroundColor(0xffffffff); } - if (i == lastSeenSectionRow) { - ((HeaderCell) view).setText(LocaleController.getString("LastSeenTitle", R.string.LastSeenTitle)); + if (i == sectionRow) { + if (isGroup) { + ((HeaderCell) view).setText(LocaleController.getString("WhoCanAddMe", R.string.WhoCanAddMe)); + } else { + ((HeaderCell) view).setText(LocaleController.getString("LastSeenTitle", R.string.LastSeenTitle)); + } } else if (i == shareSectionRow) { ((HeaderCell) view).setText(LocaleController.getString("AddExceptions", R.string.AddExceptions)); } } else if (type == 3) { if (view == null) { - view = new LastSeenRadioCell(mContext); + view = new RadioCell(mContext); view.setBackgroundColor(0xffffffff); } - LastSeenRadioCell textCell = (LastSeenRadioCell) view; + RadioCell textCell = (RadioCell) view; int checkedType = 0; if (i == everybodyRow) { textCell.setText(LocaleController.getString("LastSeenEverybody", R.string.LastSeenEverybody), lastCheckedType == 0, true); checkedType = 0; } else if (i == myContactsRow) { - textCell.setText(LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), lastCheckedType == 2, true); + textCell.setText(LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), lastCheckedType == 2, nobodyRow != -1); checkedType = 2; } else if (i == nobodyRow) { textCell.setText(LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody), lastCheckedType == 1, false); checkedType = 1; } if (lastCheckedType == checkedType) { - textCell.setChecked(false, true); + textCell.setChecked(false, enableAnimation); } else if (currentType == checkedType) { - textCell.setChecked(true, true); + textCell.setChecked(true, enableAnimation); } } return view; @@ -517,9 +563,9 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public int getItemViewType(int i) { if (i == alwaysShareRow || i == neverShareRow) { return 0; - } else if (i == shareDetailRow || i == lastSeenDetailRow) { + } else if (i == shareDetailRow || i == detailRow) { return 1; - } else if (i == lastSeenSectionRow || i == shareSectionRow) { + } else if (i == sectionRow || i == shareSectionRow) { return 2; } else if (i == everybodyRow || i == myContactsRow || i == nobodyRow) { return 3; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index c6230bed0..b4d5fa086 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -8,6 +8,7 @@ package org.telegram.ui; +import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; @@ -19,8 +20,10 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; @@ -33,6 +36,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.LayoutHelper; @@ -46,7 +50,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int privacySectionRow; private int blockedRow; private int lastSeenRow; - private int lastSeenDetailRow; + private int groupsRow; + private int groupsDetailRow; private int securitySectionRow; private int sessionsRow; private int passwordRow; @@ -55,6 +60,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int deleteAccountSectionRow; private int deleteAccountRow; private int deleteAccountDetailRow; + private int secretSectionRow; + private int secretWebpageRow; + private int secretDetailRow; private int rowCount; @Override @@ -67,7 +75,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio privacySectionRow = rowCount++; blockedRow = rowCount++; lastSeenRow = rowCount++; - lastSeenDetailRow = rowCount++; + groupsRow = rowCount++; + groupsDetailRow = rowCount++; securitySectionRow = rowCount++; passcodeRow = rowCount++; passwordRow = rowCount++; @@ -76,6 +85,15 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio deleteAccountSectionRow = rowCount++; deleteAccountRow = rowCount++; deleteAccountDetailRow = rowCount++; + if (MessagesController.getInstance().secretWebpagePreview != 1) { + secretSectionRow = rowCount++; + secretWebpageRow = rowCount++; + secretDetailRow = rowCount++; + } else { + secretSectionRow = -1; + secretWebpageRow = -1; + secretDetailRow = -1; + } NotificationCenter.getInstance().addObserver(this, NotificationCenter.privacyRulesUpdated); @@ -179,7 +197,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else if (i == lastSeenRow) { - presentFragment(new LastSeenActivity()); + presentFragment(new PrivacyControlActivity(false)); + } else if (i == groupsRow) { + presentFragment(new PrivacyControlActivity(true)); } else if (i == passwordRow) { presentFragment(new TwoStepVerificationActivity(0)); } else if (i == passcodeRow) { @@ -188,6 +208,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { presentFragment(new PasscodeActivity(0)); } + } else if (i == secretWebpageRow) { + if (MessagesController.getInstance().secretWebpagePreview == 1) { + MessagesController.getInstance().secretWebpagePreview = 0; + } else { + MessagesController.getInstance().secretWebpagePreview = 1; + } + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MessagesController.getInstance().secretWebpagePreview == 1); + } } } }); @@ -204,15 +234,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } } - private String formatRulesString() { - ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(); + private String formatRulesString(boolean isGroup) { + ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(isGroup); if (privacyRules.size() == 0) { return LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody); } int type = -1; int plus = 0; int minus = 0; - for (TLRPC.PrivacyRule rule : privacyRules) { + for (int a = 0; a < privacyRules.size(); a++) { + TLRPC.PrivacyRule rule = privacyRules.get(a); if (rule instanceof TLRPC.TL_privacyValueAllowUsers) { plus += rule.users.size(); } else if (rule instanceof TLRPC.TL_privacyValueDisallowUsers) { @@ -275,7 +306,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio @Override public boolean isEnabled(int i) { - return i == passcodeRow || i == passwordRow || i == blockedRow || i == sessionsRow || i == lastSeenRow && !ContactsController.getInstance().getLoadingLastSeenInfo() || i == deleteAccountRow && !ContactsController.getInstance().getLoadingDeleteInfo(); + return i == passcodeRow || i == passwordRow || i == blockedRow || i == sessionsRow || i == secretWebpageRow || + i == groupsRow && !ContactsController.getInstance().getLoadingGroupInfo() || + i == lastSeenRow && !ContactsController.getInstance().getLoadingLastSeenInfo() || + i == deleteAccountRow && !ContactsController.getInstance().getLoadingDeleteInfo(); } @Override @@ -320,9 +354,17 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (ContactsController.getInstance().getLoadingLastSeenInfo()) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(); + value = formatRulesString(false); } - textCell.setTextAndValue(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), value, false); + textCell.setTextAndValue(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), value, true); + } else if (i == groupsRow) { + String value; + if (ContactsController.getInstance().getLoadingGroupInfo()) { + value = LocaleController.getString("Loading", R.string.Loading); + } else { + value = formatRulesString(true); + } + textCell.setTextAndValue(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), value, false); } else if (i == deleteAccountRow) { String value; if (ContactsController.getInstance().getLoadingDeleteInfo()) { @@ -345,13 +387,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } if (i == deleteAccountDetailRow) { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("DeleteAccountHelp", R.string.DeleteAccountHelp)); - view.setBackgroundResource(R.drawable.greydivider_bottom); - } else if (i == lastSeenDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("LastSeenHelp", R.string.LastSeenHelp)); + view.setBackgroundResource(secretSectionRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider); + } else if (i == groupsDetailRow) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("GroupsAndChannelsHelp", R.string.GroupsAndChannelsHelp)); view.setBackgroundResource(R.drawable.greydivider); } else if (i == sessionsDetailRow) { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("SessionsInfo", R.string.SessionsInfo)); view.setBackgroundResource(R.drawable.greydivider); + } else if (i == secretDetailRow) { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider_bottom); } } else if (type == 2) { if (view == null) { @@ -364,6 +409,17 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio ((HeaderCell) view).setText(LocaleController.getString("SecurityTitle", R.string.SecurityTitle)); } else if (i == deleteAccountSectionRow) { ((HeaderCell) view).setText(LocaleController.getString("DeleteAccountTitle", R.string.DeleteAccountTitle)); + } else if (i == secretSectionRow) { + ((HeaderCell) view).setText(LocaleController.getString("SecretChat", R.string.SecretChat)); + } + } else if (type == 3) { + if (view == null) { + view = new TextCheckCell(mContext); + view.setBackgroundColor(0xffffffff); + } + TextCheckCell textCell = (TextCheckCell) view; + if (i == secretWebpageRow) { + textCell.setTextAndCheck(LocaleController.getString("SecretWebPage", R.string.SecretWebPage), MessagesController.getInstance().secretWebpagePreview == 1, true); } } return view; @@ -371,19 +427,21 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio @Override public int getItemViewType(int i) { - if (i == lastSeenRow || i == blockedRow || i == deleteAccountRow || i == sessionsRow || i == passwordRow || i == passcodeRow) { + if (i == lastSeenRow || i == blockedRow || i == deleteAccountRow || i == sessionsRow || i == passwordRow || i == passcodeRow || i == groupsRow) { return 0; - } else if (i == deleteAccountDetailRow || i == lastSeenDetailRow || i == sessionsDetailRow) { + } else if (i == deleteAccountDetailRow || i == groupsDetailRow || i == sessionsDetailRow || i == secretDetailRow) { return 1; - } else if (i == securitySectionRow || i == deleteAccountSectionRow || i == privacySectionRow) { + } else if (i == securitySectionRow || i == deleteAccountSectionRow || i == privacySectionRow || i == secretSectionRow) { return 2; + } else if (i == secretWebpageRow) { + return 3; } return 0; } @Override public int getViewTypeCount() { - return 3; + return 4; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java rename to TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java index ce047a7aa..3ff965bbe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java @@ -38,9 +38,9 @@ import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; -public class LastSeenUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { +public class PrivacyUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { - public interface LastSeenUsersActivityDelegate { + public interface PrivacyActivityDelegate { void didUpdatedUserList(ArrayList ids, boolean added); } @@ -48,17 +48,20 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC private ListAdapter listViewAdapter; private int selectedUserId; + private boolean isGroup; + private ArrayList uidArray; private boolean isAlwaysShare; - private LastSeenUsersActivityDelegate delegate; + private PrivacyActivityDelegate delegate; private final static int block_user = 1; - public LastSeenUsersActivity(ArrayList users, boolean always) { + public PrivacyUsersActivity(ArrayList users, boolean group, boolean always) { super(); uidArray = users; isAlwaysShare = always; + isGroup = group; } @Override @@ -78,10 +81,18 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - if (isAlwaysShare) { - actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + if (isGroup) { + if (isAlwaysShare) { + actionBar.setTitle(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow)); + } else { + actionBar.setTitle(LocaleController.getString("NeverAllow", R.string.NeverAllow)); + } } else { - actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + if (isAlwaysShare) { + actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + } else { + actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + } } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -91,6 +102,7 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC } else if (id == block_user) { Bundle args = new Bundle(); args.putBoolean(isAlwaysShare ? "isAlwaysShare" : "isNeverShare", true); + args.putBoolean("isGroup", isGroup); GroupCreateActivity fragment = new GroupCreateActivity(args); fragment.setDelegate(new GroupCreateActivity.GroupCreateActivityDelegate() { @Override @@ -216,8 +228,8 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC } } - public void setDelegate(LastSeenUsersActivityDelegate delegate) { - this.delegate = delegate; + public void setDelegate(PrivacyActivityDelegate privacyActivityDelegate) { + delegate = privacyActivityDelegate; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index e95fc7010..57d5e9e10 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -1909,7 +1909,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!currentChat.creator && !currentChat.left && !currentChat.kicked && !currentChat.megagroup) { leaveChannelRow = rowCount++; } - if (currentChat.megagroup && (currentChat.editor || currentChat.creator)) { + if (currentChat.megagroup && (currentChat.editor || currentChat.creator || currentChat.democracy)) { if (info == null || info.participants_count < MessagesController.getInstance().maxMegagroupCount) { addMemberRow = rowCount++; } @@ -2150,12 +2150,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (ChatObject.isChannel(chat)) { ActionBarMenuItem item = null; - if (chat.creator) { + if (chat.creator || chat.megagroup && chat.editor) { item = menu.addItem(10, R.drawable.ic_ab_other); item.addSubItem(edit_channel, LocaleController.getString("ChannelEdit", R.string.ChannelEdit), 0); - } else if (chat.megagroup && chat.editor) { - item = menu.addItem(10, R.drawable.ic_ab_other); - item.addSubItem(edit_name, LocaleController.getString("EditName", R.string.EditName), 0); } if (!chat.creator && !chat.left && !chat.kicked && chat.megagroup) { if (item == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 7d61c8f14..5f389d771 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -136,6 +136,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter private int textSizeRow; private int stickersRow; private int cacheRow; + private int raiseToSpeakRow; private int sendByEnterRow; private int supportSectionRow; private int supportSectionRow2; @@ -252,6 +253,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter textSizeRow = rowCount++; stickersRow = rowCount++; cacheRow = rowCount++; + raiseToSpeakRow = rowCount++; sendByEnterRow = rowCount++; supportSectionRow = rowCount++; supportSectionRow2 = rowCount++; @@ -410,6 +412,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter final TextView message = new TextView(getParentActivity()); message.setText(Html.fromHtml(LocaleController.getString("AskAQuestionInfo", R.string.AskAQuestionInfo))); message.setTextSize(18); + message.setLinkTextColor(0xff316f9f); message.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(5), AndroidUtilities.dp(8), AndroidUtilities.dp(6)); message.setMovementMethod(new LinkMovementMethodMy()); @@ -436,6 +439,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!send); } + } else if (i == raiseToSpeakRow) { + MediaController.getInstance().toogleRaiseToSpeak(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MediaController.getInstance().canRaiseToSpeak()); + } } else if (i == autoplayGifsRow) { MediaController.getInstance().toggleAutoplayGifs(); if (view instanceof TextCheckCell) { @@ -466,12 +474,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else if (i == telegramFaqRow) { - try { - Intent pickIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))); - getParentActivity().startActivityForResult(pickIntent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + AndroidUtilities.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); } else if (i == contactsReimportRow) { //not implemented } else if (i == contactsSortRow) { @@ -560,7 +563,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 2); cell.setBackgroundResource(R.drawable.list_selector); cell.setTextAndIcon(LocaleController.getString("Save", R.string.Save).toUpperCase(), 0); - cell.setTextColor(0xffcd5a5a); + cell.setTextColor(0xff517fad); cell.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -1127,7 +1130,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter i == askQuestionRow || i == sendLogsRow || i == sendByEnterRow || i == autoplayGifsRow || i == privacyRow || i == wifiDownloadRow || i == mobileDownloadRow || i == clearLogsRow || i == roamingDownloadRow || i == languageRow || i == usernameRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsSortRow || i == contactsReimportRow || i == saveToGalleryRow || - i == stickersRow || i == cacheRow; + i == stickersRow || i == cacheRow || i == raiseToSpeakRow; } @Override @@ -1227,6 +1230,8 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter textCell.setTextAndCheck(LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings), MediaController.getInstance().canSaveToGallery(), false); } else if (i == autoplayGifsRow) { textCell.setTextAndCheck(LocaleController.getString("AutoplayGifs", R.string.AutoplayGifs), MediaController.getInstance().canAutoplayGifs(), true); + } else if (i == raiseToSpeakRow) { + textCell.setTextAndCheck(LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), MediaController.getInstance().canRaiseToSpeak(), true); } } else if (type == 4) { if (view == null) { @@ -1343,7 +1348,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } if (i == settingsSectionRow || i == supportSectionRow || i == messagesSectionRow || i == mediaDownloadSection || i == contactsSectionRow) { return 1; - } else if (i == enableAnimationsRow || i == sendByEnterRow || i == saveToGalleryRow || i == autoplayGifsRow) { + } else if (i == enableAnimationsRow || i == sendByEnterRow || i == saveToGalleryRow || i == autoplayGifsRow || i == raiseToSpeakRow) { return 3; } else if (i == notificationRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == privacyRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsReimportRow || i == textSizeRow || i == languageRow || i == contactsSortRow || i == stickersRow || i == cacheRow) { return 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java index 0ce2d7da2..e2bfaaa22 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java @@ -19,13 +19,18 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; +import android.widget.AbsListView; +import android.widget.AdapterView; import android.widget.FrameLayout; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.FileLog; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Cells.StickerCell; +import org.telegram.ui.Cells.StickerEmojiCell; import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; public class StickerPreviewViewer { @@ -41,6 +46,11 @@ public class StickerPreviewViewer { } } + private int startX; + private int startY; + private View currentStickerPreviewCell; + private Runnable openStickerPreviewRunnable; + private ColorDrawable backgroundDrawable = new ColorDrawable(0x71000000); private Activity parentActivity; private WindowManager.LayoutParams windowLayoutParams; @@ -68,6 +78,178 @@ public class StickerPreviewViewer { return localInstance; } + public void reset() { + if (openStickerPreviewRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + if (currentStickerPreviewCell != null) { + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = null; + } + } + + public boolean onTouch(MotionEvent event, final View listView, final int height, final Object listener) { + if (openStickerPreviewRunnable != null || isVisible()) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (listView instanceof AbsListView) { + ((AbsListView) listView).setOnItemClickListener((AdapterView.OnItemClickListener) listener); + } else if (listView instanceof RecyclerListView) { + ((RecyclerListView) listView).setOnItemClickListener((RecyclerListView.OnItemClickListener) listener); + } + } + }, 150); + if (openStickerPreviewRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } else if (isVisible()) { + close(); + if (currentStickerPreviewCell != null) { + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = null; + } + } + } else if (event.getAction() != MotionEvent.ACTION_DOWN) { + if (isVisible()) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int count = 0; + if (listView instanceof AbsListView) { + count = ((AbsListView) listView).getChildCount(); + } else if (listView instanceof RecyclerListView) { + count = ((RecyclerListView) listView).getChildCount(); + } + for (int a = 0; a < count; a++) { + View view = null; + if (listView instanceof AbsListView) { + view = ((AbsListView) listView).getChildAt(a); + } else if (listView instanceof RecyclerListView) { + view = ((RecyclerListView) listView).getChildAt(a); + } + if (view == null) { + return false; + } + int top = view.getTop(); + int bottom = view.getBottom(); + int left = view.getLeft(); + int right = view.getRight(); + if (top > y || bottom < y || left > x || right < x) { + continue; + } + if (!(view instanceof StickerEmojiCell) && !(view instanceof StickerCell) || view == currentStickerPreviewCell) { + break; + } + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = view; + setKeyboardHeight(height); + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + open(((StickerEmojiCell) currentStickerPreviewCell).getSticker()); + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof StickerCell) { + open(((StickerCell) currentStickerPreviewCell).getSticker()); + ((StickerCell) currentStickerPreviewCell).setScaled(true); + } + return true; + } + } + return true; + } else if (openStickerPreviewRunnable != null) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(10)) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + } else { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + } + } + } + return false; + } + + public boolean onInterceptTouchEvent(MotionEvent event, final View listView, final int height) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int count = 0; + if (listView instanceof AbsListView) { + count = ((AbsListView) listView).getChildCount(); + } else if (listView instanceof RecyclerListView) { + count = ((RecyclerListView) listView).getChildCount(); + } + for (int a = 0; a < count; a++) { + View view = null; + if (listView instanceof AbsListView) { + view = ((AbsListView) listView).getChildAt(a); + } else if (listView instanceof RecyclerListView) { + view = ((RecyclerListView) listView).getChildAt(a); + } + if (view == null) { + return false; + } + int top = view.getTop(); + int bottom = view.getBottom(); + int left = view.getLeft(); + int right = view.getRight(); + if (top > y || bottom < y || left > x || right < x) { + continue; + } + if (!(view instanceof StickerEmojiCell) && !(view instanceof StickerCell) || view instanceof StickerEmojiCell && !((StickerEmojiCell) view).showingBitmap() || view instanceof StickerCell && !((StickerCell) view).showingBitmap()) { + return false; + } + startX = x; + startY = y; + currentStickerPreviewCell = view; + openStickerPreviewRunnable = new Runnable() { + @Override + public void run() { + if (openStickerPreviewRunnable == null) { + return; + } + if (listView instanceof AbsListView) { + ((AbsListView) listView).setOnItemClickListener(null); + ((AbsListView) listView).requestDisallowInterceptTouchEvent(true); + } else if (listView instanceof RecyclerListView) { + ((RecyclerListView) listView).setOnItemClickListener(null); + ((RecyclerListView) listView).requestDisallowInterceptTouchEvent(true); + } + openStickerPreviewRunnable = null; + setParentActivity((Activity) listView.getContext()); + setKeyboardHeight(height); + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + open(((StickerEmojiCell) currentStickerPreviewCell).getSticker()); + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof StickerCell) { + open(((StickerCell) currentStickerPreviewCell).getSticker()); + ((StickerCell) currentStickerPreviewCell).setScaled(true); + } + } + }; + AndroidUtilities.runOnUIThread(openStickerPreviewRunnable, 200); + return true; + } + } + return false; + } + public void setParentActivity(Activity activity) { if (parentActivity == activity) { return; @@ -80,12 +262,7 @@ public class StickerPreviewViewer { containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); - windowView.addView(containerView); - FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) containerView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - containerView.setLayoutParams(layoutParams); + windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); containerView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { diff --git a/TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png new file mode 100755 index 0000000000000000000000000000000000000000..6f77fbdcf0f0da1c1c231f30d29d29ccf4b49010 GIT binary patch literal 1729 zcmaJ?c~BE)9F0(eARq!N;I#xxK_JQISV$nH2}v+QIFblBAR3Y-WJt0xSxB%9f~c*< zdI6%KD54`3t5TIB;#55FAaW^;G6*Ot;sIFeg<85n!TwRYv-@51-us>3?53!QP&*qp z8ypU2Cs@K2Ve?}1Hw}-CmoHw6$0k>l7l(?GWYi$l!8o=YNrC}^TB?9WuvDJ0`WhUB z!&wrPk~lO@7|xU-YNFJPAsW?MjE%zu1skFjUK1gatx1(JdFfgmFj6Hvpb6fmk)8a>mwV1Q1f`pL*32tW`Kq|qS=^aUtnkU}D3FXRW(m~@Cq@drLX1k9RFp3D?+ z`JZiJI~E}YMYT*4$zU)L4OAkcQ;H|a?P!v)?${quuho{%lSG)4UC1%R8Hri|QMG92>?Ebf;{zkSr0aaqLZQUrMOD@5#}^tn@ig$K&7-ZO zVVY9^mxE8wBBu2vA9Ve9yA3^~cMVNv-gNQvE+-wFz0_CaaVUAc=Q{gs&Hc~!O|Oq8 z&*;Js42Ebn$!kH>Tc_w&P))v{Db*UdtiHlkh6X(zjFFza{Ud<(+%|UBbDxbeo_KV}zB_ zI(_cea)-bTPaJBVYKs%I(g&zHM+z4VE!&yR-lBwhL#{@4KHA^rd!g37qk3p-W=^PE zv(w=^i)xpu=s6{YR(1HNg^%KU$-C~qO3=J`9Ehl+Km)|!MPAw@~E`Xb3@0w6B&7xQ5-N=Y`-z+I_ZLdYx#l1FgG=qme8#RJ-%~k>#mBPq1;zQf;#rwDyttZ>v@;yS z^AvzO_s#nOvB||}dDcQ*LE!dxeK*TriX@F0;o@P+{9(&X(##IWud6rly7hZ6r zchx`G{9Dx4s}3k+Rb%SpMMy?~^jm*jmmfB*tpCcj@92t_x>5VJjrjMq;)C90ku~XI z0VR>Mhmqq!Vv9ycrvQ9Ywnxq1y&cV$*n?g-2P(I8J;{`hEFv9nkEvc;bo~{Wc0bdp t?%r#)eegYfzSMnWw8ww+NXtqKTU?gU-89oX)dKTRMZk;T9^eM}p57`{2#mI^Ky%$Sknc4NQ>{kXyvTBxM$wQx#FS5D|8lU>^@Jz4K=cZV(L z;wRhe8W)f`2xh?CCK)nKP{;topdxJQq6^Nz$TpqgK>08_8pWVjMwx$zm%ICY~yco%25&!^Vuzb`ij=RF&rVZkMD0rz<9JUHZn^45K1TVpnfX>O-Nf7f8 z<)oD)oK*)dkvRac9-?rYU^5qJ9E?XsgfTLohZWfXkdy0U2}cDffOfK+qP5UmZ$AW5 zPAyb|m=$K$K)R{?YK|4=E6!&$FNAH9jr0tg8{{;cYnt zE<=P0Ep#s_o7n;y7>)!HS-RArfMHOjlEE2>N(HBZN(HQxE5uhNg)=mWN~6pKR~|@= z#yMRYD{5MaC9brPTM$@{T<-OHW!`id!XDS6PBxZWA1P{9^OYl^&87 zB3$Qvu5nFn*a{w2jEs^T^*re`af}CCE?GmZor``=y%nx=?OY6Na^+$&@^EAS)#%8U z=$`O&)wbed)%YYWx}6hkZI$ee2Y_{VF;s{9#(!xvr=YvzhJX4zbQ&8>+fWnr$f-1& zZR|+K?h)@8wsR~c+wLKgu|4r`5Blvo)dF-4dZ>A8e^dKeO2JIt__nF9wEs#|sAp~| zJ2bI)<-+ag!@)Okw=B>9QGM(*wh+~7xwEL;Yy!7*-GWXo4ea~s@zz)<)S_EDc}SJj zH9qRiI}#_|_*qB%yF>8okEN!RU#Erxy1c;fU@+ZsUf-5pdob>mXTL}+7@E3(G}K&2 zx4f0Qt`=!9G-N71F|d-EvjtkHU9o6szGyRk7_ z%}K30cGbAt1?io*OR(gjX%m4JK36ac@fy<};*^Nkt z;n?JSZ){_n@x~eA7-V&R*OVky2=oT_xbjmHP;F=Q-Xz&`wWitlyKQB~0ay1$X0s!q zE@1$9fAF_5_~E(vg<#iY?eX%Q_P>pPU>M$(_)Xb$3=60>eK7xEs4jcz>!_y>w0{30 z{`%$DZvX5{?m3s!d9`~{QM6PG&z6be!3l>MZ~JVE@Bw}H(i20PJ3cFb&%Jq`Uwn;Md#>Y^{i3@!4RMY zq!ARwiYKzxotgC7OmZ~XiuvNby`gU4 zy&#|`fB0b4aga3!bde*|T8=?#_c}6-WT#H^7<&{e>gE5JRl8SlTlufB*mh07*qoM6N<$f;YJ_lK=n! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_pause.png b/TMessagesProj/src/main/res/drawable-hdpi/s_pause.png new file mode 100755 index 0000000000000000000000000000000000000000..9fac4ed3357b3d1ee2db7308992645b6785e9aaf GIT binary patch literal 975 zcmaJ=J8aWH7&cV0prS$`mUKF~3n1cG5|dbUtJqH3ARI+$pc!%OYhqgaT>FaMOf3vN zBxcqEONR=vGca^OFd;^EmM*X`Ac4X;jnfVU%l5s#@B5$kv{7H0nVy}dC~Bs*tT)Mc znS58y(d57L!o5X?46d~C3R=UF89=IRqYeZ$*X+V3H0|xpk8qx%rWmKy#%<%aY$2C5 z6AT->K4DYT{9^2z);h$X1G|o=FyG(3XMkfX%xb~l4PS#jXSpB1m43Zt_1CSE%`7f} z`B)|bF2p8?-3>34V}%*&%4D8wa|{?l@VderJJmKCKtllp1vZzpctHS?#0vR>BndZw z$O|IJlUK?LdAT6T;!QAm7-B83*W{*N9oZr)h3R4J%N!R)5gX-L6m&VER4OGJqL?L! zY`E=VGtPS9T&keM&Sk?ZV$o~St)KpF2bx|v+WkIMERJB@F)uLJ`R`Nx1lyY@s zZMo3HDc3&X<|cBJR&ae{S%-o10NT|6xnLNw>`eBBpQtzD+LL_|CUQCA43`x4RH4%? z(mly^+_q#fZhYvGZVyOXb9<|w$d%A)dbt&U?ff1L21_(eFVL+Y=b!w_yq!8Y%IwmA zKD^w$^tgEU=WF`;Z2tb|{qo_Ly^HN-CST5`o|mAd{$ Hz4!1hL;f=q literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png new file mode 100755 index 0000000000000000000000000000000000000000..1965bd3bed063df07d94faa821484f84c904b5f6 GIT binary patch literal 975 zcmaJ=zi-n(7&R)gpi&1A1L<^fB?J<&V<&NA6Sqoiw++HklteU4;MkYMr1ly6LYz!3 z3+(_aBSI_;fY?C-i2<=75DbVvp$jYsbwJ{rCMg5KvVA}F-uu4$zIS_-^7_L3;yguB z3#ARMO2*UVJ9C02|Lq6vWilkN-oQ1~!hJJ5Ji^H zWJQs`2!s?ba4GVNNj@WIMOjz|a zSVIt!1d$8}9yX(-7cNZ{G#FZe<6{STAXYS+sD~AXWO{f6*PqII;kZnsU|eMS9M7iW zBTayY@qei6PSGK*!lQiuDIC@ZKIEz}M7_WwjcYB%p?p~lpovjXM`&wO#YzWZ6n2mg z)S3v+Z#tfh`r(BU-Z12n7h==1U`bOLqQE+iEla7Kpr&<6m5K$P*RwfIPwRqI6x6Jm z$w4_7S%*lN(#X^+{w62F`70uLZ~jqa(}C>|B;->W#Vf>|Am)xg1G` ziyQk_qbFO$J@IsETe6rMA9}>?0kQR0{^5OcCDf8us7K$LuMYNqtPi)&%9Cm8Rrizw~GDe4BZ*GNFk@!!VxQ%Jn{B0XHmne3t zzTfZnexKea`N{FF&V!v4MRnySG6gdBkng}=Kl%T@h3}A|7iVYi6e{D2VnZsap%Mf+ zLz#sIsAx;4zJntaMKgMF2G7XHB^4R0;$c|Vun3!?Mn+vrQRg8BB{-{_apupB8w}93 zI5QoUdD%+CIelW;hEvOvMRj>zjcLs2Q8404M8JSp0j{xNI+7b_wsj>k_qI6(Y(wyT zoOzPejGPB)WJ3^T2SX|^2tX8BArciuAqc{}5axLDiXkB)MMWt*1a=;VM66Ik9WsRfkf|A!jJF51Bb_%z@D6n2VB7UT-hL5sFZ z8dvV~LRnJUh6+Y@5ut_FDdy)8M$R0vKzd39N2YaCLltLW8!yXJ&UCP1sxX&{Gem*a zbxleqqgin%l1#@^NkPa)hxxH|O3Y?cW65Ej7g8;52C0h%G;xcoJ>{m_ay=^;7KxmJ zwtgCFV>U9tcFB_7K9}LPdOKXLeJ-)KT#h8ed5!&7qgz|VJ>GQJwq&tud}tE4+r-wj zPq+T2C|`FjlPtP-O8-21G)f1?sdZ*W7R#k-^?u_0{q_0U=c~2jH$QIt_Du72aQ(T4 zxpL4?UrcQF)Tin7;M$q3#NNO=bh7};Yq$BpFTN%Vu2YR}4|O83`F#B>wcfvWrbhJz z#?#-P+tUcHyzHkt5+nQSZ`14h3BT$K9P%||iD1WR>B#+#tq=XTZoUaFfBBj6;(I;4 zo6k1!OPyU0_cR_R0{Z4eC^Hr1o0B)_3%5?bcNWe2`igJ~{Y@c>CDKK;Gz1E h?=SkT0-vb*sEZHZHGh6%^&9WD$Ym!pms2M{dJHj5ftvsT literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png new file mode 100755 index 0000000000000000000000000000000000000000..56284c35a42c074ec55e62a70c144a9d9871f0f1 GIT binary patch literal 1190 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv}!3HE>9xS;9q$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%Guf6$kEc!)Y;O>(a_M<)X~+=%*oZs+0@j@ z#mLgw9H!SLKe;qFHLnDwHwB^B45waDQpha;+U$~Alv$RV;#QQOs{r=0RVHq?7~?b# zsy79D$8ltNatP_`#^EDWPzH!6d?B))q6~MWB+y)78&qol`;+08sadxc~qF literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png new file mode 100755 index 0000000000000000000000000000000000000000..8039e1bc79dd1b910f19fda3df0428ec85e1c393 GIT binary patch literal 1018 zcmaJ=O-$2J94|psP>7L)fLvaR2Q;i7W9wL@VqI5QVkd4(*ueu``(O>UueJ|YxCmSf z7Y-WlTuF=}UWoA^CVs>NUi6|S#^}`q)3_|XVdn*|I6?9`+vT*$?SM%$GHxQ zqB=7ZN{+0(;dk;l`G2WM`()|E=_1af8C=mlNXaHDL6EWaS(t;mxp?ah9HppM+A0)r zQM)D@$Y%5q!vwZV*c3H77Pz`G2QetYS<8{=y{FG;V3`s<71ub;O~JA?vE;%0Qnp|$ z%^69P9=i-i1Ca>W5bGeY=N(@RB)Y0Al6`p0(x3{#a}s?RR8gA*Dda&AXNDsN$MZlC z7(Nyk1bzraIX=pAMCp{fv2kHt6^bOB)v4tEED(WS)fF+tldYFRkHe?;YRwhy~Hqc#` zXSgt>I#AR854G(E+Q&I~6z@NU{lcOP*&OuIf@hG%%?yODTruTA9V4%R(0sj$lVyaF zUq&uStzl1|mR3NjXK=-@inJmSWia>G%uUE*1Ro^>0Vs)uY)O#}aL-SL2$^V;OGB zWl1n>*x0`sT|Xkz6K)%0ON_?gLx)VeN5=ZsYvU8S5>7^u3&F?I{=vam|C#H@zHT3E zp7<>9ng(^Y`}eyp%&p#hyR!pcTc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`VqjokYVK(2Y-a9kXy|HcY2o7PWNB{TY;5Lg z=xFQ+)9aF-T$-DjR|3v4~Pj*wm=R%;iu*SQ+p9GS%2!PSqsb(Pd!~6Ln>}1 z{rLaiURuDP<`S<^X<@n~x9AskhK;fU{}~_64d_vhUBtvDw1G!p{;^4w>CA@8ldMDzpWN8P+HwAo zrtYehnUPkFi(Xm_Xa^lOQd8LH>k_$Rp47C~NdZ501t&=w3&blN+_d_HOwi{@Yk}93 z7sPSLUwYphw(NzS5ZfcwDPb8eLU}muus&*as1fYA*?2>)LwRN3^Tf?LTNLEB@*Le% xUb5-6?1@cBOE%^3F$Z=3kX;*ngn^Nb;q$$puP(j4bO=-kc)I$ztaD0e0swigeRlu= literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png new file mode 100755 index 0000000000000000000000000000000000000000..041898e9fd092c49f82516917df94bbb7caf41b3 GIT binary patch literal 1372 zcmeAS@N?(olHy`uVBq!ia0vp^@<1%j!3HE->_hZ{lw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6H#24v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`GuBNuFf>#!Gt)CP zF*P$Y)KM@pFf`IP03tJ8LlY}gGbUo-h6WQb!1OB;3-k^33_xCjDfIQluQWFouDZA+C>7yetOgf{R2HP_ z2c;J0mlh=hBQ8xDWL1Hcb5UwyNq$jCetr%t6azByOY(~|@(UE4gUu8)!ZY(y^2>`g z!Rmc|tvvIJOA_;vQ$1a5m4GJbWoD*WxmviI8@af-I-8lh7#g~oI=LAcTbNl`y11G- z8dw?_!SuT1Czs}?=9R$orXcjX;nWLC3b_S9n_W_iGRsm^+=}vZ6~JD$%Eav!XPo9i z^`_uv@OxE{=c}*A?7%zCbIEGZ* zdNXaW7qg>C>vdlxv9L)lt}X&B&8@8oqAaE_gnzIkX)g<5x)sSOX4bVtaLpIqD{hWK z5*=cJE~;Hh{}wFyq<*qW?al$KJCfzgI~R!WOG-OG&pYk?yfsfP`cfT~BUtqxu<*?M z5z%(``JDG(IcEL+bz@p2uh(mX7hkfIZq>v`-EZdJujY98*=YqPwF9yqP5k@Sc(1a@ zFWe~I>cc~9<9WZ&ZNHd;YwfDYAN3-?@r+lV(dlpCS9TS;SgBRbQu;sc!(yW5d zeDQmGw)rodYwEjWMbiGcH(y_{Fc7c1+zwp9jyHSKmJ-RypH`#vwFb-&y7*M4S5ACXVmTVpJQiL z^k9$KTgDA+TI&)lSPhR(+14Pd=~0$B|1$S{p4x00D=m&mw%VP|aNY0XYrw;I(E98FCXTG4N}(s7^OtY+ kl2+Nz^wRjs`Cmc_3=b^iiGs>IPgg&ebxsLQ0AR)G0ssI2 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png new file mode 100755 index 0000000000000000000000000000000000000000..00475a7217ec3e41c687b9aa0a4a83dcb2dd7d12 GIT binary patch literal 1399 zcmeAS@N?(olHy`uVBq!ia0vp^5{{auq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%F@Wx+0D(()!EG4&Ct-*)Y942(#gfh)xg-m z(A3Gr6sFfDKe;qFHLnDwHwB^B4X0jEQpha;+U$~Alv$RV;#QQOs{r=0RVHq?IO8-A zsy79DJ)dxC89~7}j5e*XprXCOzo@{{}c*0N31E%&OV6y)FN$)5F1LJE?7srr_ zTU(}Ddow$Vv`*G2(<yD-W{@dmm+T{Za3rZ?&5Rr&fK&13k{VuTf`nSyYfP+vkhO` zS-Urz6!#^iHm#obD2ykk^FPb&6y`^-?pLs}D{$3ZeRf+=d@)bZf$Xaby6;`d*~5JF zl{in+q`nBImV@j3@*>kNXc|f~xH_sFd+L5*=>-06w!05lbv%6jJa9}pkijOIxU*)D z<0K(bfk`vIG*)*urWGBWxx|E-|HmVqwpDLD^))Q*c8ze>zQ`1|^L1&#YRla#zx&^=`5aboXzyR`%zs(e-yT|GDPW># z$5rICn@>{K!h4In*4Brv5BI!a_^hDIvDs2^v2btgt=Z>1kCtDU;WtnB^pX|J!%wna z;1AmJ(k+n9^IG|VWpS#nUFZFKuEEi$Q1R%K>IPn;FYNbD-r3J8!4NWY($7d~Zw*jU N=;`X`vd$@?2>=zA`9uH! literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png new file mode 100755 index 0000000000000000000000000000000000000000..5fd37eb57480b08021751ccc3bd360a5ca2ab3e7 GIT binary patch literal 1165 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y2=9ZF3nBND}m`vLFjeGsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6qsIL(9V zO~LIJXPkQVfsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8ti5zHs~H#=89iMbLn>|^ zneNMV$UwmD_`L&c%2)o?1FsWb@mvii2v_qh(b%q0bQ`GG<{#GAKCpz43-r~u& z=lg*ZIw_K$-fVhtY}5Utt@Hnso62zNT0}c>-EVuNDimaKcC+fS1FIQ#csOyNn|7gP zv&xo-H-*GL=x}QP$l&y@nBU^9y5?cC5X*jvLz=t!k6C&h=`3ZenC~LXemmts7RT~C zLid!{Idd}<&sY{0S|O9L>(&L&=QTgAF1cH@vMk%5n92EPtKig02kN6YZe{7S>{+8? z@Z93sG>3DoF5XP4;YKTuDA;_Ddbj1_oMT5a5A9q#^Kz5-tl;I0&$%WX(Ry-k>9cLm c^BLI~lDc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`;pSxQVrF9KV&PS$mF)9aF-T$-DjR|3H{644~kf%h=vIPQxAvr@^7+kA zvEnX^FFNhgevqyrWLXe9|8?PsIs+cL9~lx{vqX6FF3A@C$`^Y(>xJFx=VBQS@3wDm z%emq4{pEjys+&spGkf$KcP~%86#u|#M)Q_y7H7D3Eo^wB{p`5IZgItDKfTJ`&xY|Y zyRpWvzMjFl@oVa<%jG9*KYv=7r7X3NEmwhUm!;2~pV37erpwpby5!xN8Q`hPrT#V8 zmdnu>=bSxq=lg+8sl76fHWtfmD(w7qDJSV! z;lEbJze>-T3r~NNOZgOQI_1TljG5xT>ME%Uy_uib&#E5`d*M}~=zBBUZz<1`&pp;l z&Pe`m)j2=aAlOx0ciGkD_f@<4KfYXfCFt_%7|?SjwDD%GjKcD=2Ve>e9)|F$VFTT6}}Uy>>}{WGucOfPjO-D~=ejqR0B_toT! z{Q0s~;)k)#C@yj)X=XxGCxNG|1x{%4Iy^KP~VkZ8w zzM2xNIpOp!#ygTe~DWM4f=KDWI literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png new file mode 100755 index 0000000000000000000000000000000000000000..001f109bd8042ce97e63b21ecc58b0d3065c3a49 GIT binary patch literal 1294 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxSU1_g&``n5OwZ87 z)XdCKN5ROz&`93^h|F{iO{`4Ktc=VRpg;*|TTx1yRgjAt)Gi>;Rw<*Tq`*pFzr4I$ zuiRKKzbIYb(9+TpWQLKEE>MMTab;dfVufyAu`f(~1RD^r68eAMwS&*t9 zlvv ztM~P_^2{qPNz6-5^>ndS0-B(gnVDi`?(Aah;$m*#V&Pw_38s1qYsK$q=<$I0aFi%2~V~_4m{zf<^fZC5inVcYRJShFfcZGx;TbZ z+)DcM|Gz!6EhG0zscUPakFzgvY5Wlx5OAS9=&SL>hbIaY=J6e|d-7w##3>4_zs~V_ z$hH*8Gj6oJFkL_6rL(NcHXVW6myfhN%x~n;V@--yc;-B*iu=gzh8^-RE`JW$D3B2; zJ0VLY;T*rhImRff=}O#<(;928x;k~RGU?uRnAYlW+Na@)phBAZ!9(f}Ihv1{l;K0`5?BTc6;eH{rW~~wTWQPTHVnMYl*p4KnM6KXEGG|HD317E@Lk#TuRvc12 z=&|~c^z_#MFLMMA!rz zWuUU7GCl^zDudibA4e`>_h2;d0kEwcfF97+ULgLAo`aFO0>HNBJEGGL;*-^tN0#dW zA%vD|wA~2=sbNquJVdReB{EGA@0A@x$Hf65DuwJFefXVi_bg z2$KGSl!}L%s&eZZA>Edy>Nc4@pYf@nPM zE)}ti(@-j22dfkNi)X8@6OG6WIZbG*?*&V~a*744vYQH}E2rFWn~CCj(*xiO^MtfT z)n5bTX9+i=V{j6HlQ*%b3!y}O7w|rNK1-B_<@^A{Oo$zWkV}C80000Wl8E#W9iBQ+zAeQm7NK4V|7n*j+1 zB)UM?3K*CoA+a(ru&^*87}*$^7+4r8m2;Y;9SGLR_uuLJzW;g88uh!2^VjDYhFLV% z^(NgHGJ7sZ|F4#xSLt?*)Y@bNZ;`}~5Tm-dgMjJV+o*|bclW_(RAHENtk-Ijwsj9W z*yrpF!=-*m*$h)zOGDe~Ap$yR+Y1!-*N2ZR@LYx6ELnmTYN+e24@gpK@3xc9qB@9XV*LnMiA0d*yEtuRs(1_LZHO0adExUHqkRS2~R*#t)|jCUqgY;-ZfaTkX`+mOJ` zO)qe95-*SNmIciqCU)Q;Q&(83ztv|i21A|BLoyhL~{j2 zL03RdMmb65OUa@+t)OVRt6=a!?v1)#t!|bFzW7OpJ;p*!lHxcPV?cB0Z0|?4%uWnWjt}Ggr*PEV3b9nj5!s{;Z(MgKbros`#Wo|fNyx^qinShLBf{GB=m||Y$l&OZ-0OL8D}z?lbMNMFD`xB-MfE0 zc=u-q?mzrsUw53dU)mjT=IO0-yVG~Uk9+N#JMh%$ws7Im)INRv^<(|>MD(EI$(t9!lj4+3FY~2aI}g^7`din!`=ShEz^NH3%d_nTI8)XiHaK!8Aqr zX}w&*75So|B7;#p4C5LWVN+B(>spGs05Pb+dELy=U!Odsfv#of*@PUCtpcp;lgl=o zS)MAZ%L{5sqqFBg+7*a^0kHyHW6^X3H$%5{1v2-xSsJt;cp*a{Bvp~8K>^tiB$!xO zjc^>`d4`K8c%B;v(Fhl1Bjn}7TwF--LNo~uADTq7wK<_AP8`M}s|;Po*b-Q_*=#b+ z7=!G2mP@5lo<=kpCWx@JWMah)o6cxkL4=NK>lW6L2|Pumh8j3SlS~heU|1bl(>W{? zDH!W27Rxaa??`Q+EdL*B7#*~OOYkV)e+oP0B@418=%9wJlE%%AdZ8?#U_%8XyNu9c zyNc6wgppH67AVZ{;LNOUYN+XqweYemNT!1oQ-zY4p@{;c>zYuE#gZJK5(}w(j^m1n zTq4Gwjf=5@m`vt4G2Z5iNNpI<#BHv2#4UE^dR8zj5?O?{eidpHHZnl#$b#NImwZ>f zL$206mqJ%AOOj!|#{Sjl_7-uEH|^M#EIP)ACULt>Z2jo6?=!g)*Ca7lc0bnk_V=^? z(5`Q5{NDPB7enCN@Y>Feja!vq#0spfOYbP(^%d6_+6g`E37qzCWyeOURe$L9%7^G` zqvt0V3S3%weEWE?`fU4rdar-`*YwQYL%V|~2gH~0@h~@d_x^+D d>0+<{*bue({<~cLu`%M^PN_I0Zsx12e*kkyMcn`Z literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png new file mode 100755 index 0000000000000000000000000000000000000000..f5a735089c7588081fdd30e420f842f6e0ae72b7 GIT binary patch literal 1081 zcmaJ=PiWIn98TS=V{B{;6gR~^Gmr^u{&Y=T;=0*3oh#Z=y5cHcOp~`RY{|=#H``6| zKUi-b1;L9RM3^4biwYgMi;6Nq*zh(zc@o`45!9D$?L1gRlJ|%2`+mRo`+e_vYUF5h zV@D%JQO${AB~8XA^0hSh$$x2;Nsyr($Fq18jpKsqKq{i690Und&BHWQ_1Wo{u%Dvp zXd{!w+2nCqLnfno7^Z02giTTXgGF1_CLsnnm^Z92{pDGi28JG{$Al!8v}16>7@l+B z=-fy~o14@mogN$j{Y9Awm=LR=XiizKTny9ex-yx2+bj*%A$T%OZzPpXra%li5C}|f zK;w8Gh$6#>1X1LBK#=2uEJt23z=vc(l!J%B=0lTcjy^7@m7&d8WEG|-Ft%luEffk& zp_f5Up5-M;@-%|M06_%YSqrPhfaP{o6cp%cj$va1S-?|Nb7%&KX_D#25lp)(Yq^_c zA_ZfMs?G8Y=N+j6OeX&iHO(s8#c8;e?>~jz%&ZOBG<4C7qmjmqcX^>~Ip#nWBPWB< zRHcfk351b5fou>P6+!oyVd<#g9$d#KlXAjxv1(~Bp@eCoz!-)uD?@Q1$Z^q_6piqF zT#$sQBnez!oD+LFF%+qA6{O9W(83k2zQv8z*`jKU$b}mv) zy-luOJC{gJE=!VOy~h64=*kvxk2kH_mMp5qhZb?WLu~!}Y5FL+67vZqk|}=3egFM? z@Wq?4^4Uw-U5f{!!cNdpiRu=L%%Gpxp z`M%QHk@Mj0D*yh`tp@3HOQ`M1jh$C0anIXr({gI{Wc0Rw`zc@RtxxGD|I&N8xdcmz bdCKRf9(P~M9H#f~@-A~CKB7E`p1%ACO#)Z; literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png new file mode 100755 index 0000000000000000000000000000000000000000..af519d761cd719fc6fa31cebcb7b01e65597fdb8 GIT binary patch literal 993 zcmaJ=&ui0A91p9^QJn19?cy_2RIvHA_H}(MZe7y4fT^?XSTBNU^0tO8c`;;U?adY!=VA&g(f)-wPeU<7bD&M9wK%&^`bcD`~K*DuVE*6W4 zhN5H{A{%Y{)QYoyG~HLwab$;XKwaX4MA2%IEvoV?)59Zp!9doJdSzk-6Jsk7WkE`g z)CZd8|Dm2YKu5HOkMjMeaMaiiuvo(p*$QpexV7mdRDiS)Ta<(iLN@zVTy7IeqBaSD zR)^sHs_Q$X6J6-yO%oY@L@nROhOY8VL2z9MDatII&B1~O3l&)|=ND%Ra#<;96{wYA zrK0z_IBJR@{=a`(y zWX?>!PQ5LS{<;@tjQ1x#yn4BCIuoaw?|$DsE}g8352hB*rk+0D{q|5E+v6s8M_Rkq ek255;Y=UTPwhc+{2Z&6AK2;A>AD_%qq^g9eo#J<^_(NBZTELNzy$jW&-3G=L=1)&_Kox5LziE|2HVHbapc5Y!*0Hj_%lJ4peW zfDF(L9@)#XB*)RLKfrP93DW0feT)~soQL)E0gm?t$*qUN(M%=7C&bpRSa=ntvIrSG z!{l-~I@dr$vyWjzp^&5D^La4BV-4#_vOT(0msb#hC7Y^&RH&1VqLhY1C`{o@H;caMq4NWcJlqFu$3G(0FwX~95Q9xxJ;cB%HRbP zNC=uq2nX_2?94(0tt>Q1p_?P?dsJP4IqUcaJ|5>|x`iZN1~D;AVFg-M72fX;L|H*> z5V)Ygve7^!*b))NU^Lny_#>g#);w2)@{k5}l;+AE!T+Kf_nuvGbloHnMb|0>-FJ6k2{km+r7yTtOcc;cq_ht{R?p^2~vyZrL zOA|Fk-nUP0WxIY?PkN?JS&L%uEbUem-}=^(DP8NUT((=Z=;wJp6S3 zeQ^2w>XppBDi_?H?rNOfKfzw><|f~iF5DPR)lSZh-W*@9k8)Y}gAZ#-?^@}z=^EE~ gk#MJI(06il7eRloi&bBL{K&b>v1q$E+tPdS4;)fn-T(jq literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png new file mode 100755 index 0000000000000000000000000000000000000000..ea4c131969e5741162c9e08b136670a707380a43 GIT binary patch literal 1144 zcmeAS@N?(olHy`uVBq!ia0vp^qChOf!3HF^2u;-kQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMjf~x^=xk)W0@Le~pIn-onpXnTn}X15iBm5qDdZLaZFWg5$}CGwaVyHtRRDY0DigO`%y60q z)tiFbE#^4&>H{644~kf%h=vIPQxAvntyCEj?tIEGZ* zO8W8tzdf_y4w(*nhL2_nY3fVnHF`Mj|L@LF?(}M=L2BjR~`1SopNKJc%k4OTaq77q>N#Oq~^Bui%z~|{AjQ8 zvnnY$UanKOQB9q#i`(XtMeHobBl{Ox$olq4c9c8C{$%Pfz4-NUcdeqrKjtIz3r?J7 z{OGOl&vMJ;DJlZ%Tb@k|4X`s(h?RTsSN4D4!MrUE>XC9H%iFVdQ&MBb@ E0HOkWiU0rr literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png new file mode 100755 index 0000000000000000000000000000000000000000..e4ee283e285afb4966f4bd834364d87b64b47b1f GIT binary patch literal 1174 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRx!3HE}ruUu)Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMjWoqnbY-VZT=4@u}W@zYY>SW|*=4fo_X69_+ zWaegI0@Le~pIn-onpXnTn*!HsXn<2MC@JI?0Bv?jEy^rQO>ryA&s6|>*(wvaTU>CO z2i2Q`(=7(BIQ8lS9itD5Sfq%C2?0|NhzU=&Kn^_Nr{)1udl4{M7cD*WjDdlX%hSa% zq~g|+$$z;R9Yv0cKYi>wrGM#^JuT`FVy6U63D|d^^{J$XhU!PIH}XBjrOU2uyQa6j z?(Mm|mg(>B%ru-5bWHqJ-2J~DSJ$&e{h8bttFw_cdBXSPfUxW`qn#$r1(;t3TU^C{^V&qv>qqjscGVdf~ORY)3 ztlY-kIV=6HIZS#V$Y01eXD2iB_Qg6^V;tnC{J=wx6M%|ppwGV)z4*}Q$iB}aAJ)h literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png new file mode 100755 index 0000000000000000000000000000000000000000..d61b17745216f1a915640bf7e747f6fc6bc2a950 GIT binary patch literal 1123 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{1|(OCFP#RYBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpgi&u1T;Y}Gc(1?!otPe(#_e?+05L<(9qS?(bC+++0@v{(89^d z*v-uarq?AuximL5uLPzy1)t_MOBT7w^i1Y~*c zVDmYY_sK)}I+H<5{*xJkaaIg763S)>PwBTzYkYZED>~|7@@qHu@4f3!*Q&m8e7rxC zr+(@KW0uEOxi8*lKCokJFPp+9$5LFqKlMO3*OOf#Ty@VKJneJ0F4*$<_=c4)|0upW ix6C?C({gbg6A#0l+mkBNC$3coWqVIoKbLh*2~7ZQhkJGa literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png new file mode 100755 index 0000000000000000000000000000000000000000..41dcd5a948d898258ffd5872431639946a5c6cf1 GIT binary patch literal 1793 zcmaJ?c~BE)91UntR7ypt=g1Nwr%BjcCXrxnO(cLJC_19VWFZ+yHYN)Rc&$ND)DenP z0}e$6MXHF^#;b^;Xc1c>Hr`Hg9MK{$q83!FN;fLlKT3CY_q*PEzjJ2`6XNFkjGHzN zhr{_u7l;(t$Z|hpy|8yp!Q7eHFclFeBZ+VtVo{kO9A5*kf&i&rl@2K&l_qC(3lxpR zjUwoj$w;z1mZOICWR)93w(5--8;6UYXEmzS84v=jg3@&cE}^&nJOR*YxP&DPd6e8J zgtWQ^xh5zvH%_U}%}}#7gn2PQw3UMi=pjS}SoN6(Gsns$eAMM&bN4od0DOcX8C=3A zr;_CffDkr80E0{;siQy;U^2-doxx;+vjJ)pNToz!Ht+)g&f*3gzip63fTWDn1luiNJY_?m2N+n?kk~znKsH`M|Ie17x1ew()oe|N& z2EeVTS_NkzTmt6lrx5hUVOfLubDFS(QLHK>1tdqgLmC3g<^K=W>xa>1L;-#A_dkWr z${Zs^Q9x!m%cRB%mlo_cW#kA=kP3lKN*K-@%3^{RMqslRHUh##CJ?qnXVAbFbNENR zT+Wdi%!taMhNL1c0aGCBbQ%twDF*3O0ZYUZP(e`45K!lcB-A+!P(q6m(m`;DD}vQo zddPqbaW!AK>=C){R?r(U%Oc36%Z4-(6RZb5hRo58>5z0X|D$iB=OkxRjxp|}hC zuR;%PVcp}N4!13~7;b#XfOWeGYim9jC&s>(EUAdEwBGC4E!R%s`!`!$%knPAzw_jC z!?tWq2;fg#w2v@0BGQ&S`JGlS-|4UgE&5U3Q=M?6p^MM0869sM6QBDU7}q8CUGe_n zw#vG}pv2^+R!w@gCHr{Cg+1Xv?UZiFq4hT0O>wQB5!|wi>Srh%)AJRF->~8}t#>5-@VOFns&Yd=gV_B{g$i@M5ZsR_5ohq z^;hmH9VAw52zJQF^U#~l<*4jUJ-`}_ZaqC9RFYMmC&AG6~ zljJ+y*_XIYQM$GHfU0Zb;FC=Te)_Brdu}_Yc8Ze=V;-AJBBoJ_Zti{+2EN?(eN}O# zWb4L*2)^c89(s01NE_PM6^N!0KZN?_^a}p|E;N^SZ^9JMm8nXQTCCa7p0_yis3xp~ zQM54W=g=k_@$$g6(=x{5l9N*x*?H~7Zz`Ic`~&Egn(pi6PbQS167E}CNd+-UX_xs{ z*uFV2h1R;X&SiUWJH9HT4}Cs!VAkt5GYm9f3_hr(ENf4MZ(aV$vD;5gy`JQ6IvBz8 zJ82)cz95OXg=avY9KtOR8xSt`B;O7=-W<88k?lcXM&^HgB|Pw^T!v3|)?cdirxGWo zoH!jCTq5vdUq)SV=-J1+zpb@8MwO@3<<|r~I+xWZ3o5H_eB_7(DESl4M3?Q#zw!9t zcsRZ_q0#Z%r9TQ{nEbzbPS4-?Vd*Q;zDd9_u<8X`ee1@`%s;uEmNOw<#dZN<%)5Q8 z{OyOldW!bd{u=JFzo_jvNV>gtKZ*vog~`BYQqzNe1rbFf@!qbWgT>2hu!B_ST4e?~ z)_27%dj9rJ_&e%OUBLP9{YgJ$-x!-67&80*vxkfl!Ft!#&AK$F{l(gIPyGu5v@hY4 z$DyT5l#}o8fB9fM$pAhh^~r!FmLu!_J67DJ5Ff8~q+bH?xb#u6_U;8x)0zPmuBH97 z%k%ls>(+*aA&q^Cw#Rv1Wq<@%B&=t*uL)(J>b)3z_0jK^&e2HV+oxTF3wHLGZoT5) zU-)6?b?b{A9j+t(ecpWuNu7+jy_pu=T=dwzc^+Q4w4)bd-?qtU?w^uW94D$1q}u)g DN$a_@ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png new file mode 100755 index 0000000000000000000000000000000000000000..56a18f14aa298afa9384c98674f481585d79dfaa GIT binary patch literal 1542 zcmeAS@N?(olHy`uVBq!ia0vp^79h;Q1|(OsS<3+_$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y2=9ZF3nBND}m`vLFhHZsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6s4IL(9V zO~LIJ6P$YWfsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8tpD7b(agZWRORX77*cWT z&8*YjqJc6E=g%5#Si;^FwBW(A6J}vrjuRWZ6g*c@$k=s#|QT8pZR&-WK9t+t+N}Q zm)ZpB?=XJF`sruQjKkj?Z2vU&FSXuubIt80#l?cN5?SjGd^btGs5qllb4J_s3)937 z=2dX8dvDu%AbEvv^Mj?n+vJ-kX9}#jl@yWWn~H(;lA-+0_L8zDg34ZQP!E>aTwP^@KL@vSX$P zs|(DRc{y7#ub=RyT&eq$!gkMfSsGSBcGV}>8DC?WxZCGbNHXgW)>{+jn9p;an60#P z{m!=O=YBFrr+%<{V}7CM>qn#N9qvn<8 z4lVezXQloPiKn@49haA}Nc;3YHaiknbUshG>GzbmE3~&S-x7N;b{fm-Q@NM^>{+24 z=&^gjr>3|I+*OYHFIe|3s5|KDeSRm~ejkpqNTDf`Epls{dX5*VgzIpg(ny<>{^HKN z&V|ohcYg4lRLI_S#r*60?R8~l+w?o`@VY-y$x4`&ZYABVATG3VPO|9YKYaBkH}f9* z$a-96?cdZEd#Uz>rA6ki4$Fva@q5;^$(&zU#Czk_MT}2PF8%b3eW_ynK(;{P!4Auc z=`N0u6$-ZbUhqo9)6)78&q Iol`;+04%9Yi~s-t literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png new file mode 100644 index 0000000000000000000000000000000000000000..af215a34c348d76a36d8cc79e02e73ea1efca570 GIT binary patch literal 841 zcmV-P1GfB$P)X`>T8RT(mYL0_aU45w!133trT?XI?3rKf-PzfhG#bSoGNO7P_8WfAX2Nn@|AEbT z3-k%ZK}R5|b)^4>pS1?(3JbrR(?4WE&Nuh2+OBv3PHl&r{a0_GUm$>}`gl*gckv*kJYl>3T`;PbBY>!SXam|( z2nc(PUjYN!1p*is*mAq+U(OYTZepng^BORh`iw6OZpTorS5&{?#+BoN{k{*Qp zp>tBl0J0)#q0O0sP!L@Hu|g2^xB)h&gCWzs4jzA3IS9ko1Z+?7n#=}aG5)x!5JqDL zfAU`-RIFcd2t&=7O_D*}Vtbe10zc~l0)0WB<^zEdBNH1nf}kZf62^;o5ISs@b(F>Y zd#OO+A_l&&Usn+5Tg*aD#)Qvm6)Ed1^l>T(`_=xboR`u?sUOK_jDyfg6-hzpYdi=w zQ}8cTK!CcT8AOI6$Y6;O1U-WUOA{a*&woh`1ZZ^vL`K=>s%d8o#Ld^@JV6LbcUW-Y z7(|^GS98xEu5iL29#I8>zK1~Yb-EzY5dhM$Ol@DuTE2tr17rK#yh7zAbg zHXvd^m{-FLmZQPaOrIv8nhdB+h^=xFu<$U8E;w*0O7@9(`~6}xF|$Jsg3CY0WvEt7 zst(7AW^j$%_y9g9rSrSw)A?qDCsINTCmj#~aWHkukIE*nrJ!dwGCVHvgFlfy$G_4 z;6V^P?O#ylNkn9N5j=SCDhldZ@F3_x9KLjI=V3J@dA~lN&-drMw_d$5Gd(*E0GO$) znl(0FV&Clfv+V!)aQ_DzF4J<8)=7)@oEU=@k8EOC37j^rVaMCud5aeTnBx3KlQ!)& z%_RZvWEegTBE|+_aXF0~cMDUviQ9gtbKhSaa?tm5ZbP<3J2G&`U+u@Z-mf;?{+6qH z-0~7!Of@DDVCuj$*bWmd)wzML#^%|!z`+58Zt2{yQ%!pv8YIS0=JPpMLW z`~T1&7^4$f!zccpDx5TSBP`T#Lb|cb3fG#?OhuXzV~3KsLCE$fi|ZXiNzx$^H0lbx zy5WZ&=_LyTylrchFriN9;)sq?BB+o6_WrCLe~6=zKGUDy&>0|?29;&D==q-tg!zS zdbGv5C!3DjmMzAOk3-h&F>CAc$D=uRCCrMs(nvpid-rq(zzb8a_x?QF)9*{*;u%U7 z3Xh&YD0Hjc_xqpPFTXsr$*=jPbAy`%z~{MxwL|{s;CJp7xbx=b&nr7$QFc@*SIsA- HTX+8ghO08D literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png new file mode 100755 index 0000000000000000000000000000000000000000..83e9e8201c273a466f61753828ef5374edb72d07 GIT binary patch literal 985 zcmaJ=&ui0A9FG$-9SnyD-FA9r2Ni6Rm$um&8b_P7u4roM3M(GOGA1usJFmwDpkEW@rd4U3Y>GNfjN(`%mGp*7uQ6MIr767HwQ}C3fX2T7XP~gBr%$<0@9#nBcIDeV}d1 z;PRH^*|-;88R88?DS06=Jqwj|m7@y0A70;sqy;P!4HdN*(LVN{+WgM(*A7p zJvo#3dFu^RoH?X6{J8k&ws`ODvr|vcPmIdm&ZX${lLeE#^P4%rG9S*Jy?Ah=`8>XC Mr9xSMnZLX92M=j9-2eap literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_play.png new file mode 100755 index 0000000000000000000000000000000000000000..2d98d4cc3551a77df6e27107f420e34f08532873 GIT binary patch literal 1230 zcmeAS@N?(olHy`uVBq!ia0vp^58U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMj<>u_-WaMV-=xpiaXlUqaYH8r)Y~ku^X<%+) zW^U+Y1k>x1pIn-onpXnTn}X2mgi|jlDdZLaZFWg5$}CGwaVyHtRRDY0DigO`EO43! z)tiFbEtWX->H{644~kf%h=vIPQxAv-Do`UEd;Z+;(WJV3A%L*uTKci#ew0!h(BFYrgOtS#WX20=2N92b^0< z|NgV6|D@iuc+2%VI+tXW2j1T3qeA&f<9sauOeG zW!!$DQI(r{Ig6A*OD;F_dea?Eaw57sd&(ZN_HAxcINcu0aZZIrmAl!1rCg}V6-4`Q zcAD^gMGc4EvQ~%JS>Km%*0nlp77J5h`D?(kYOnIGDFRz!ImBWfFErV7u~z2hs)W=J ztjhyDdD`p`Of=c_YLfkvAFJwi?Dyc^nQYxS@!P`Qrzf%|w>>v3@V03$-7zOLD)K7_ z`@`>RLd)h~D7pCi{RbWY0$o?LOaD&RwAbF4nf@c5?V(V0WzsaC$VZAiTmDzpv`u^|{Z)!(ec>;XA|CpxvMn#?#f$Wt~$(69C~ttA79h literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png new file mode 100755 index 0000000000000000000000000000000000000000..f0993b74231a505d86d759cc4a9021d8578908af GIT binary patch literal 1245 zcmeAS@N?(olHy`uVBq!ia0vp^58U}fi7AzZCsS=07?_nZLn2Bde0{8v^Kf6`()~Xj@TAnpKdC8`Lf!&sHg;q@=(~U%$M( zT(8_%FTW^V-_X+15@d#vkuFe$ZgFK^Nn(X=Ua>OF1ees}+T7#d8#0MoBXEYLU9GXQxBrqI_HztY@Xxa#7Ppj3o=u^L<)Qdy9y zACy|0Us{w5jJPyqkW~d%&PAz-CHX}m`T04pPz=b(FUc>?$S+WE4mMNJ2+zz*$uBR~ z1grP;werj>E=kNwPW5!LRRWrzmzkMj<>u&QY~gHd=4|QYXlUqa>SSqY=4fbO;ppP% zWME+E1k>x1pIn-onpXnTn}X15j#DovDdZLaZFWg5$}CGwaVyHtRRDY0DigO`OmLb9 z)tiFbEv7j2>H{644~kf%h=vIPQxAv{Yr*99?u4UpDRPK1d8a&g9 zJJ)w<$Nd96f1D!jq&z#|o?w3F;eAW%%}1ASKhLzvNidGf($p~Q+@APL@tS`aUY|4- zUwYInfnP6C>(BucUfmn53pto4+T8Hn(d^dJm?`7;FrxWEUP4rZd&V>7#S*M0>V-aER#V6j;E`i%Q~lo FCIF##tH}TW literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png new file mode 100755 index 0000000000000000000000000000000000000000..6cfea5aa05db7c1a7366a547d01181a970a34e03 GIT binary patch literal 1072 zcmaJ=O=#0l9M3)+V_0=KWO^te8)9{BnyyWk&~EG6ZY!8E+REx>G)rFBuq7``-fUMq zOwoe}4=O4M;sm`;ya`UW(?rFCmkHwVYsf@pf8Kv01=Ym7$9S+I1b`KlxL=%fB-?% zQA#p}Qo?awf~rfjFs{6+V>Uqqdh)s`O#noWfpJ9(QX3B!DN>Px)QC@T3wju2mBE4m z5{03pRG5%Bnd<2#19=_`r~rv%UY*oTJ|Cotx;)-n$23J2A!s53rA#B7#N| z!pU+KhqDktGYfSxoM6c#BZ?-&oardy1%Z!gCK5FX#3DfoE4UOz=9!S&$9bY`nDzHF zOw`xq4RwWCj_dMrtS{fu3SA9UsW!RgQ2a){?+L65uP4vTNztyR0bbtc-jp-*7HY|`}j)SiA6%m{Hrh5 zLrt|zOE@v*9PQg|EZ8`=H&vbnQRj*1C3~jPzT5$R&@~N2?f1KH S(28Txy2G*PP-MO@efAI79$J?G literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png new file mode 100755 index 0000000000000000000000000000000000000000..9113acad4c99b894133d3a7dc2857f2239df429a GIT binary patch literal 1247 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpgi&u1T;Y}Gc(1?*uu=n+|1m<+05M8(9qS?(#_4$+0e|z${qPpvE_2Lmnf8R|^8!d#yUIHMF)pvtrz6Ch)&C%y)T* z_EZB#=2i=i4*4X*?*;;=69fAbElp)Z*pB@FaOI7DLqua7Uy;fK2?-01BRyXVE=UU9 za_HP41v9b@rpICmX&c-GJQ0Q3YTqidG(dyQRtTyr~4ecYhoIBJG2`sj0HXi+;+UNh-caZ zF{Y123j5fO*f&JTNolQgSmUz#l<4$kx7qTG`J_rOY$&_1-0{ggeFgTnk}iC=ShXY^ zd6zzJPC0N&NW{t9K{DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_cg49rTIArU1JzCKpT`MG+DAT@dwxdlMo3=B5*6$OdO*{LN8 zNvY|XdA3ULckfqH$V{%1*XSQL?vFu&J;D8jzb> zlBiITo0C^;Rbi_HHrEQs1_|pcDS(xfWZNo192Makpx~Tel&WB=XRMoSU}&gdW~OIo zVrph)sH0$HU}&Uo07PcGh9*{~W>!Y#3Q(W~w5=#5%__*n4QdyVXRDM^Qc_^0uU}qX zu2*iXmtT~wZ)j<02{OaTNEfI=x41H|B(Xv_uUHvof=g;~a#3bMNoIbY0?5R~r2Ntn zTP2`NAzsKWfE$}v3=Jk=fazBx7U&!58GyV5Q|Rl9UukYGTy=3tP%6T`SPd=?sVqp< z4@xc0FD*(2MqHXQ$f^P>=c3falKi5O{QMkPCvax^qDbT%`0F*I~Fb#iqyuyiqTGBh?e zF?OgeO}d2cGa#^MI+n2$-zRZsuQMU|>A#>Eakt zaqG?W{oc%mBFE3aO5tu=(7eAukMGq3H4TfChnPTa6@f9`O$-0#|x8GYpp zGC%j6PmtbHXs#;!z;waK1shLtiBOzgb{yB+1nHV@d`trcB}aa()LzHu_h-w@d!}N)W-C2A z;@=vV;iIFSl=tVy>td;FmE{r1et+U8n~O}oX4)tIy6*oI$pW9*-cIwEC!1Ug`zz1H Z!|=B&&3(h~)i*#zoTsaw%Q~loCIBH-^gRFo literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png new file mode 100755 index 0000000000000000000000000000000000000000..b47bd668cc5c745d1063885db79bde893118db7b GIT binary patch literal 1504 zcmeAS@N?(olHy`uVBq!ia0vp^3P7yJ!3HFkD$jfgq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%EZ{n(9puj#o5f<&Ct-*)XCM%z|zdz)XBxw z)yc%k5vJEAKe;qFHLnDwHwB^B6{lWMQpha;+U$~Alv$RV;#QQOs{r=0RVHq?IN>x8 zsy79eu^-`w?)ytl@slKb5 z)~NVhH_3cK*YUiB8@2KqB`A=-(AFj&%J`>-#tN%@7j=}U}4b!JH+g%qWkam2SXjE?pb?k0~Qz?9OL}VsJ7{Vez(DkK_LA+}&9=aYil8-on@DKcB{d2KsO*(5;wSbIuBxJ*vhg@%~w={#$?n_~t4n%vy; z?SH?`^_S6+3!Q$Y1i!rcrPnjRD9R`3q)(fM-}~9d3k}!qacknCx# zKa{hrcAfj~f8tT_thN-N>w-@k8G9{Em#9j1T((>-_0jg4QI?ly4eOj{JGt3&E+2n> zVh2mS@9rf3m|o*|O}9*c=HB@~_qWMf@dd}0>B{r|;G6LCWs>xi+jX-7U)yNT3XNv| z{>R?wo%=rC;5%*qHyacj-o4)@qjq+k0%z39UZ$@PX3zM~{cXpV^^Mh&UE^6K7*vD| UqdUL&NrB2-Pgg&ebxsLQ0N#u=`2YX_ literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png new file mode 100755 index 0000000000000000000000000000000000000000..8419721d4e16cdaaa1398dfe77aba50c189fabe0 GIT binary patch literal 1288 zcmeAS@N?(olHy`uVBq!ia0vp^S|H591|*LjJ{b+9BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFe_z-M3hAM`dB6B=jtVb)aX^@765fKFxc2v6eK2Rr0UTq__OB&@Hb09I0xZL0)vRD^GUf^&XRs)DJWv2L<~p`n7AnVzAE zshOFfj)IYap^?4;5Si&3npl~dSs9rtK!Fm_wxX0Ys~{IQs9ivwtx`rwNr9EVetCJh zUb(Seeo?xx^|#0uTKVr7^KE~&-IMVSR9nfZANAQKal@=Hr> zm4GgVcpgi&u1T;Y}Gc(1?+{www#m(5<+05L<(9qS?$=uM=$;sK!(%Hho z$jH?hrq?AuximL5uLPzy1)hV_}6DLRvaSH6z&kW@@RVg9N0%ml^P|8$IVYmG^c%o3t}6S@GqK86H|@W|P`{8r<8-DN~Bonk#Z6 zZb|lc5#iS@Uo=l9CCr_;FIP_Zbt}(GS;>g}lnnb-2iX)&UGq51Bv$6msokKZviNZM z!BrD^GUTTyflghUfjB-64I;i#Z+2vET;N?J{p&92v` ztcElb$}G)GYU#`xm1Y-{(J?Kvns&OVm1(8cVw27OvF-VtbH2;(d7k%qzxVy)+Zz(> zZ*Aphg+L&z1DJGYNDJeCL4wWC#$ld<5upf!V-+bp8HAt;;1~!95cA?74#X3v zwp@dJ5C}6+$c<1$u!2Z@Sd8IKVK7Ru)W}94e0-Hs9zOw605MRUP(lWW8k#^rC?JFD z2rPG&)DMamGE-$xSZXkrpPIn;7J$AKz(+|k3Wy;E4^WB|C32FI41Urj8Rt{mSP=LG zQ6!MTKTSojLI6Kl1_1=j3N+sxhXaU249K&z~=`v zMw1C*NgVp>&#{avG8nH=NJ&_1N=gbQWd#P7#bI&Y-riFhcs$yOK+9DU1y6~V$epGY z=#ZQ*6G|0ASOQEb@?zj51sOCt{WArz^oy)S{`r`U2ZmMhq*xrreJZ7CAdB_?pn86vA>KIh-Wp8w(ffG!;rp@{>V41uWyjaN_hShQz}PSRM~c0lzRJ z;JQvI5x^<(WuNdY7AZg?SMVf!D1c4|jS3i{P(Z>HXkK_PPa55ehR5L;1TVTLk?P?` zSdH_h5^!Fg(_A{tPZC2C#WYv&7uWBr+^JR&OO27~kW82i30BKsG4Ls6lJM(ZyuYgV znJf6Z7wT8JSfd&2RAK+C(9>JS?wOi?XYpUTYuSB|N<3E@$ZJnNyGMFc z)Y092(6Th{iMf@jMty5l{Ml7y%flt3Ce`cFry8rxs?v%5&QiC1SZ(+zbf_O}vB{*y zq#>Q1enq`6qs^r@so6f-=AdO1f}8H5Zs#PJX$oo_l$3$jr_^tD?bm#NWUgxQR=d|# zda(Us^NQxeU0MzBniNHudCwFR+S&1kf~-j2JUrec?M2Gvv+9xFblw5~GAqPIYc(m-aDhn4%3S*B?@51TV|api@krTZC^lv}SZ3EBUT! zIT*SJv>w4?q zMH_2!T3Xt}M2UJ=s-0S)B9lhcqg1M^xM|n;U8b&r&X_o)9`~J@w{3AJGl9j~kVZlAnd&A;RIm8^ZT$+XHp;qn4ic$FXa2M2y@V(GClg{|j{wzGXG%MLdV|au+K( z|CZaY3m~-CYcBcPTH48jiPyt9)+Io7A5?g=BhlGFyj@Ui*|tf(Kj_&G7CV-3cTMrCn{R86_{QPxIej;&?rm zd%xD;;cSS40t}Uz#28U;%l$4@fbMwWL?Ave$=ychqOA#JO)ji+wb3otdOao+Y;;aq z*AExSPv`)b%?UmEVK&l`&t1Gb7SNh%<}p!Ekdw8DoYrMD7uCRr`F!Vm+suv=gD=Z8 z16R{d=4SpXsy-!E`3@CuuT8Ej0__B{j>O!6rY1R94(8~(ENRd>{8;OlLz*~>qjA&a z=<-IMuN3^m7R9De1#@d7F=xV0?U7e#fT|4x?9i(dzNN<#H(r>Ng)MR+$PX+#n!N^< zch2*sV{1EdyZO*KjL;rY&F+cKg007fu4dfI5n9hLMcq|0X zw9#LQ9&As`8ZRXbZe5R(o&C5#IH&wZvSxP<{iy9PmQ}~lRPbAeU3VP&Z$!Pn znq41vcPMRD)Q)b?Lf>Uw!h-(TjHc|4$R)sY|1BRE#!VdFBA-VY*Vj4*j(c4u7ghIa z^G$57^jsx`BpT9k?I|y><({!=l~Ze+8=owB5tP2_%=UqpzQe;~A&27fvR96lX@4la zJHk;O>Q0Ch(1JtSPCWaunlP&OKeAqbt@&j7o{feW=*p{qL3?^L-lc07*)_jI4XOur zMq-X`|E;rYD=Fc`@IzF+{SF7f#t~_qX)!C)g0@fe(b65UaUzU|WUT+&)IBDE5llZr Hi{AMkDEZd8 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png new file mode 100755 index 0000000000000000000000000000000000000000..d7f1b935c383bbc82adc938305fd2c228dd9133f GIT binary patch literal 1801 zcmaJ?X;2eq7>>nyq~d`Q0j;hZ(IDm|2Lu9R5|C)Zkwn3xNXRZ`!DMqRCP6$%OtGHz z7!jyKP>_OG@xW@QidL+&iYQv73M#cYL8TRqI1bVciuOn8&hCEi_s#P>@42&ICB)73 zCI%1*1cJ9DRxHO?rRNzj41Z6~99xSo{#bM}ra;p%v&sk)=0Io~3`n%9<**!9K~}>R zID$a%0ug00mMoL<)u@)H@?dBdtsZ9+2oX^hy-J-4V?Y|b9MK8DuCwPr0D%Nx5=X|6 z=|!*xiOn{`itIS0Iy+Mx27ytLK!k;l3us|X1z5BzbSAz<0QT$haoclD2Z4SFmMH+= z1(hsI07R$}1~{}3s+z%M0$eVQ$>wmm%-H~o!DP`H_|2s<*?bO{&*A~^FA(=;gwpwP zam;&P_)Y+7Fig*<)6Hfx%^X5QjmzoGu&^+X28%_-5mb{^hp8-7oryf4Acjq9BcjI; zR0ntzRcUAzCIInB-=(0{e~{Ig-j@k47~P`M)0s4eC#3DLKhfli^A8SsQ^9KI4td@x9C@n2d_Wr&}rt+&hr>#>p7tY9& z1l-(g678al6B)@Wf6_!+?6mbp%Bu8$3nvw%OWx7kpdF%EL+;OxwR7&qhBawg_SN*> z3;p%UNq0)#t0ix&E;A?dc55fE&3gEytUQ6@H{*v}>- z@SfKZ`fFS-(qhp6Si@yQRqbRVb?<}JHS2aroslt<$vIP>EnC%kwa;SP6<{^sx0 zK);9GJ&R6t94)&ZMfQo$op^t%c5W|3wv2gZyH^s(2`OXU9J12pCN>_j@pGs3qB z={C_wk}r}1CBlZn^(llUJ}YiOhDQOK`S$BxsYSN!n-9fZDShgf@0d4c&C*88D&lEq z<7bR(Bd^-JW7>R*q~NJDloyOWm00EK*{%o5W?@k+Z9h-Fe~Mu}Raw5XrR&X#>a~`a zLU=>q2^a3iK4KSm^W~P1J5EUFZnJ_Sl7;?4;KL!yWbJYnlnJ zG|<}Xh-WA$4mm~SB+YYo9a3Ja=fux z7Jqx_vhV7fEAPyA_Qh~#B`3x_bsam-CH4l(Z`gF_+~aea7Ct(8!uhJcXK(&}FUQ-c zn!_bPn3~j@-3Th{bk8$-CKg{V9#+G4KQH`JhRO_GkIaEvcYfjT);Iq_2TdcJQ#TeZ zy2`j@E;-P>y*K~p?nd@cg`@hupO;+~F;GD1p4Zg#g!W0BFU*geUEujSNuuM#M}(=i Fe*ilx!u9|F literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0c72100abad6807ba598908c78ebf2803a0a5af0 GIT binary patch literal 1412 zcmV-~1$+95P)y?2NVsbKh%5UiXM8esU$?qo0Sx@L;)3(|R;r}%Kj4$*!b$W&Y`5R%T*+yz> z?Syz|GI`nxAQ=mgg*0t8ZLft8o>+W~I`vzH1jyod(}&6mF&5r_ftHYsoL4@su;K|7 znLbrYh#-~+?3zBQ8Sa|Cu@_=I{B?&XHcLqp=Rs1s=%QsjE5kzW)8uVZQMOejuUL@ahDuf^FPnqnDU1OP6h@UtS z!i)50HJ_BXK8X`2r3ztRM;HkmZC2VVMTilh-lPXEf%FaWz;INk5F=vYHM3Fx*}Yd& zenagoM2HW=+dC_6Gb$I6x@I`bT?lJ80>N8AAhgI;2r~hJ*zICdlXq_+KKkMB7i((3 zE6q@7IP6;pQuGwa><^xhr~4AZY~4X*PGWR7gCsrNo9YHg%ndiXxLuQOucUF1m;1y$ zz9k_(_uNT6L)t4ZtEQ6r>s>_H_7eP{KnCd7*D@g?I z&r;p0?PQs@5P^_mAg5%sBR^6jqLnTMa!NG>s^gu6fPv3}A#j}#CgTz@N^WAIY_@Al zh>=LX4pLkN87%Bu6N27V2SJLnUG_v2fy`X|ytAa2QF+|#NMNv6sRP;$mmS_r@)AOu4p@M>c4YQkjAWU|KcmC^DQ8#*2v zI+!?Em^cEVzX2%>jD9eKGckk1F~r0%1Xrm$SE(P~+?@>`m75SGt9EZ-zgAW?-uqDpHSE6;r$J=j z_!-3&8N@A_(i$i?>iU%wYd_Zlyr!5eh~27TFXsZhYbB{8bqxe>8rKUcNo}1+dwmpX z-wcW?(w;fCU>Rg@h^4}hEyzsXaH~Fv8s99BQNCA05$;vu z80GXecH*y>>Xj0vPnkXyL|1V_q{2Aguehgg+Vr7dnu-@<)$M8{L#h;zAWfUQxHqdO z#QNwEIYFJA;hRdO{xogOc{1iD#JV81hTd;0^K;mlo5NnunFzcN!C&?~#<3K$BJman==|2E>7efHAXTtY9fGoJHedyscIW0hn5U=-+A(Ul zreBjSLV+#J*{@AO>~Va6Ew zR?emuu7G?j69E@u6U6R@7s|0h_jP5mPp(-S^dY#V(1%Xd^cA3@00NOor!0==fg~|} zMwBFe4hS4CupIfM6rYhrNfze8V9>-`V6V#+tu(MjP72+`*q2#0iXtXTGbm`Vd@h$u zGz1|<5UH@^VKYv7;p|XBgP|2TK6a1?5=FC)+E}59r-vc9{z%pf2WcV+V`I~2d4@|u z8Ul6w|4`Q*p+j7ONB;g(I5avwWGgU4?Z6_1Tc1r#`LY^76QjUDXk(bgl_tU{Y$6}1 zRS8^Nb37YG;iW!a*X6PoV$-u=SyO1Dz&MUA&u6%zRxAl>Zn41gMKP-tbE+z4MNN~q zbV(X=HDtA2=;0yPKH{dwa+6kYePUUIfpZJmr2x60AF}L>_k|m)H{jaiec{J)S>gHjlEbL+p+~wsAZ>kL_{@(*=y%Vw7}u4+c@3hTumY4X;FEqO6{Gie18 z@gjKBKfuHA;*hC_q2iCLpq{*JR}X>+yGZde@TF_J9jqbA`@YBL^ZEXK5Aw4Y2KtZm zGYm73n^6mNJxRY)eFx~j^7yAnm%}7mB6E0wgoclpjD^bxkBO35+MdRXesw-%&=s0I4IUU#1~M2mwl5qZecifz49+z1x-RA1fEccca;nTy1*B8+5}^mGQoY-(JAf;J`! zDM3)RbW&?`RctOh$R%yAwaeAIa^q2OJnC6RzI_W>nvWgOOj)wK$D(xAYjLgav8Y|S zJPn4A8@s2`?ISupvDq10y6Fr)a_O}DbgXZGe&0i{#MPXdDMp*WzP=dv2!@m^$1j~| z;Gv^yJ!kXG26%dLWoz^0_22N>%4%49lfAaOJ^ln8yT7sCcrq9>_;>(xI&Z^I+Z`}I}t-d>) literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png new file mode 100755 index 0000000000000000000000000000000000000000..4757ae74d92a7490d9fbe6414ab5995f90cc312f GIT binary patch literal 1435 zcmeAS@N?(olHy`uVBq!ia0vp^sz9vA!3HGPM_xDpq$EpRBT9nv(@M${i&7aJQ}UBi z6+Ckj(^G>|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%F)8y($dMy)!EX?(a_M<)WX@x)zZ?y%*@Q$ z$l1l%7^c@HKe;qFHLnDwHwB^B4X0jEQpha;+U$~Alv$RV;#QQOs{r=0RVHq?IO8-A zsy79DJ)dxC89~7}j5e*XprXCOzo@{{}c*0N31E%&OV6x^vHo=;Kfr;PK#WAGf z)|nf=9wC7e$3D)?)L3i~KGCULAyY-bX;rLC&}y^XMF*H}wQe=;kOpT~Ol4 zQryX*nijY+S7uY>4v9-s1Y0?q6#@?RE{yxnevf(borOPlec!|XMSuGL zzuM?4S+?BmXgU(m&YAN-vd=pIsK?w7|9s`PpW)ag^!a6_)cX%|=`p_X8}A%pVk@}u z^~=vx!SGnW`SDQ(&DSkn7X9K=>#B}8cG$>XIzn?c+nxjBF&BbPJrgpLaNIjBNUiY8 zL+iY3&D6^++kZ4{j`F&B$3d*wBIxCGm$Oz!U#Br#&*t;=*(ta3kjZ1=V;5E|opM%o zr(jh|^^!$XI(NFbeH0bnI%QMlVVQZSmDVhp^7rf#pUn1YL1xQ8uwAxT4peO#d3)Z2 zj0>+rR3lBT1#*}A1a0itCv!RMluVe_W3N+BE_QqJmfz=VE4(MRX|_rDOjq%JnGrVi zj~Unf5arrErE=0IAY+ zEoJ)5O9iujb}!%bY{{yhi=uk3r0<+C-9*N%{-NEi?9dgnf~r4FP*&XSzJ8i`s_JEP z{d)eH3g#b|KI^~pXnM0w$T^SR$AWcj8~^-Ye}!w;N5eP9Gvc=ywp`o5Eh@cIGqSj7 zomrHjr08a*^^f(|?bb;-U)#$1-6ZG6cUB38KO6lwM$0}`0~ME^u6{1-oD!M|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%F)r(!qUmn&>2J+x|%u~m>9Y`8CV(`xtJLl z7?{EIy5uL9=BDPA!1Sgd^cvyR3rY&P1wfl!Qj0RnQd8WD@^clyUbf1_=@v^joaRCG zrr>sq0ZzU8K*#8VA{Hs4VM4&v17gCHEsz6G_^Elo)LsNk)~C(;MHv{FBs^UlLn>~a zxnb)uHBjdG$LIG{L@&qm2+4H$I19L}(mk?WQ((G*hoksK4bhl6K22>gP69G42dzDL z7j-nx+@%ub+@b%o%P}c|%gy4)tUCXH=NJ8~d;j@Q{Rc^rBl6GhJ^w$axaRWyZ89fS z-&p89_lvo)@cvK1M!q$Rm7^9%ific5GF2exhK3i?(*?X>%^5TM9wjx##>-xWQ9OdsRh8sE4k{=fG}M&``) z58D?je@_J*_ogk@$L(+H|#-%XLLwO*NXXGBv{DyrAZd zpL)B`XrG`|NsWB zHQ~~_``2{MJkVXyB%{xLb81xiH~mk4jp}XA&tqU_xEGxzUM6vBC8*r=boFyt=akR{ E02Rm?m;e9( literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png new file mode 100755 index 0000000000000000000000000000000000000000..4601e79e9f604af3a82e62411f1ec82b0adecf0d GIT binary patch literal 1183 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)yeG;lO=HZykvvP~UL%}p#Voy^?~%q(3D z%#2`qUGkGlb5rw5V0u#!dQEZa1to>t0-((%M%CKY*LngWvbo4>bzJv-GI53kNwA)`4nM78V-zbra;{zvGck0stU&Ua(zDieYE$oZ`%dWj~u65 z6@qmpoHWV49^%a_l=^gif=aoA+OFlxq8t{gZt_b~y8C+nMW!VQynPSk5?=0puO{oh eZ*wK50mGiTRxdWcSS$=GGCW=VT-G@yGywp+IEz>S literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png new file mode 100755 index 0000000000000000000000000000000000000000..5cc0a860e7415986ec43d9860e7e9a54962003f7 GIT binary patch literal 1464 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL1|)l2v+e>Z$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%u1Od5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y2=9ZF3nBND}m`vLFjeHsTY(KatnYqyQCInmZhe+73JqDfW2&$iQ6rfIL(9V zO~LIJN1S@~fsWA!MJ!T8!-RmT2gHOYTObFX@Kf`Esl5o8tgHUMc)`HHq~q!07*cWT z&CI>thaDu^^&h2wOx~zh$K%J>#J5NV#ykq6ISbd-s?)6&$f!S|0j ziFKluE305&hPa^Un}CV)_J^f&3#Pee?sql`3aA^dx-yd~Xl6{)JfS@;B9j)CG(@htp?U9% z(N-bFjZQ5Zs@+77|KAf=9(9Z<(ro^@M{C>Sqg!T(T~3Pf>CQCd4A#21 z(}a890ojVL#YZ!KC-T}fs23>Bx+m`N_DaP)<>JqOa-?^hknkvYEz=}5*^p;*^B$pS z#>{!uN(u_QZ-|`N-(7ZOjg;^5-y7Ks4X-?_{G(y<<8uGf)EPEm+!Ge%Y?S$K-K`nM zpT;G#*z?SypibQeE%sxPEV)c#!U958q5hdUUyyG^j2<* z#h>K6o9@TnpAs%QyTq}p^R>>C(4#MI?JD%_`NY!{7m{{wY|6H_V+Po~;1Ffc1+hD4M^`1)8S=jZArg4F0$^BXQ!4Z zB&DWj=GiK}-@RW+Av48RDcsc8z_-9TH6zobswg$M$}c3jDm&RSMakYy!KT6rXh3di zNuokUZcbjYRfVk**jy_h8zii+qySb@l5ML5aa4qFfP!;=QL2Kep0RGSfuW&-nVFuU ziK&^Hp^k!)fuWJU0T7w#8k$&{npqi{D?ot~(6*wKG^-#NH>h1eo~=?wNlAf~zJ7Um zxn8-kUVc%!zM-Y1CCCgTBVC{h-Qvo;lEez#ykcdT2`;I{$wiq3C7Jno3Lp~`lk!VT zY?Xj6g?J&i0B&qvF*KNf0j6J(SfFpHX8`gNOrftYexnUy@&(kzb(T9Bihb5uTZsl3!k| z30CjxYvq|&T#}fVoa*Ufs{}MbFEca6%EigV(#6f()Y;73#n8~z)Y8bp(AB`e#K^?h z#o5r@4W`#6Ke;qFHLnDwHwB^B45waDQpha;+U$~Alv$RV;#QQOs{r=0RVHq?7~?b# zsy79rK=~zrzLsyplm>H*UOOpRzEXQFqOjpzs?G8xGw#SL4F|ZPVc!ih{W+b&N}tW^g$l z6?k{Sb(O%9ZLfD+f8tk_CA7c#whC!KjwX^FNytj z^!pt*=7Omg`*MB5=N9Jv3u-J54EbE@J!h-QdLe07Q+dsTLyKnZ-*_a_`*V3ioLhCj zMXT)R>kY~Wm>*1TINpBcSzgi4l_g$M`@$ayd`^lx(_Lw(|Lo|VAeIK>0|ExBJTIdT zgxx+=c7ZQp%0^RDB|h`FOV6@%TTMSE5se-n-RwwSJEP7kB^7o@_a^G-HjMcQtb6;!E|LHzH>)8G?LGowwrPcB^Kizn>_^0{dC*`hk zKy~txYR9{5w*AW3mp|jq_A|xnK%LNY*rWa4BX!Kx+H1w}!P zlmLRrsR#;cTaH=PnS{O`ra1Jgv?vWmCp*M10ttg+5VaTvF>EOm4FY_*I2H^A#nP0` zji4t6V}h53M<5Y`Af^P86U0UgK_ge9Yz)TJTcZ?95mIR516z}Z?cxsrafE+}`fJUCEP%$+u{Ciy{x;C1Lc;Gz* zNnqhW1Qj6=0vrei0Xl)|CLxi@0E0mw)94Ha*%hFW$P^+89Sk=zjY(%PDel0>2akG# zr7_GcVO4mF5+sI#Dkuq-poNQZG`dnUIWQm zhz3J67WQ9-o-(1`V_be}TXgfO@j(UJ?J(Nb&#Dj5(c5yE&t->edT!(ic=JQ%)gNum zX~$E8T#Ji=kPuSC4OiF5d$Z12@3qnLr5*JpE~NrOJjl&Y>v7uAj!)Z~ExMamQn}KU zV&=XrFqkT&ZkjZCef5c6b^qa=+>}|{^WTm(k55w7qt&XGYk|(XxkrnwkA!XOD9svd zeXx2nO;`6;>~l(U8&{dpC9AQ0deMB$dE;*Ern*y%{!5y@`qsgr{>2MsPV}F+zp69v z(ZQCVFGXNDMJBH5?Zk?05ZoKN z{+6Vx#$Nci?ThR7>J9chHV5>FAI)<)N3opQYS?4HD6au`-g5zPF4f`CPyjn9rs$8h z?utG6OUx~o**Lc-anG)vscfMVc3HFP7NW-NLj&B5sAIX>jAkrS{BpKHx@V-LLYuBn zxp3i#LR6;VH{(aeyDko1#k4Q){(9KXqLR9JG7X>AnV2)nZZZCX_`K!d|}P9bD4I` zcVF^6hXa>8t;p7`Evw7%9nZuVx+2pZY`VQ=u)4tF>2Pg%lkKb3dR=<3{l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)yMv>2~2MaLa!xGy`ZF!TL84#CABECEH%ZgC_h&L>}9J=+-@<$X&zK> z3U0TUtfD)fMCJq-j{b;<( z@Q3|8L+A%l-uZWb-1{r|y|$^V^Z6Ftb2)4Uj(4IM!jG(FDe#K|KdV;O6NuS*?pFU)1E5xp*SAieM@ z!@h29Ru0D)D+i57L5#otTmAkR6Jv6~Ji_bA=>@_aJ2D!~W;`{Y$Ev0$^MWi4!H@6%k$GFWw+j8mJH@RMqwSf`KQCl^@F@H5qs-Hs zUv~uP8+^3Bc(%t)fidW)``V>HGUi=HL|*c5f-erAJzy^jHFf!l!PRbcl>;-_y$wb)@uUFxv&S zb;0wL8o~nF-?L> literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml b/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml new file mode 100644 index 000000000..8d9ed5448 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/s_player_play_states.xml b/TMessagesProj/src/main/res/drawable/s_player_play_states.xml new file mode 100644 index 000000000..d5e885d16 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/s_player_play_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/identicon_layout.xml b/TMessagesProj/src/main/res/layout/identicon_layout.xml deleted file mode 100644 index 74ee98109..000000000 --- a/TMessagesProj/src/main/res/layout/identicon_layout.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ar/strings.xml b/TMessagesProj/src/main/res/values-ar/strings.xml index 77bac871c..8f1bb60c8 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -90,6 +90,7 @@ إذا قمت بتفعيل التعليقات، الأعضاء سيتمكنون من مناقشة ما تنشره في قناتك. إضافة جهات اتصال لقناتك يستطيع الناس مشاركة هذا الرابط مع غيرهم ويمكنهم إيجاد قناتك من خلال البحث في تيليجرام. + الرابط يستطيع الناس الدخول إلى قناتك فقط من خلال الرابط أدناه. يمكنك تعطيل هذا الرابط في أي وقت. الوصف @@ -117,6 +118,8 @@ اسم القناة يجب أن يتكوّن من ٥ حروف على الأقل. الاسم يجب ألا يتخطى ٣٢ حرف كحد أقصى. أسماء القنوات لا يمكن أن تبدأ برقم. + + جاري مراجعة الاسم... %1$s متاح. أعضاء @@ -128,6 +131,7 @@ هل أنت متأكد من رغبتك في مغادرة القناة؟ ستخسر كافة الرسائل في هذه القناة. تعديل + يرجى ملاحظة أنه في حال اخترت رابط عام لقناتك، سيستطيع أي شخص إيجادها من خلال البحث والدخول إليها.\n\nلا تقم بإنشاء هذا الرابط إذا رغبت في أن تستمر قناتك خاصة. فضلًا اختر رابط لقناتك العامة ليتمكن الناس من إيجادها من خلال البحث ومشاركتها مع غيرهم.\n\nإلى لم ترغب بذلك، يفضّل إنشاء قناة خاصة بدلًا من العامة. تم إنشاء القناة @@ -169,7 +173,7 @@ %1$s قام بإرسال مكان للقناة %2$s %1$s قام بإرسال ملف للقناة %2$s %1$s أرسل صورة متحركة للقناة %2$s - %1$s قام بإرسال مقطع صوتي للقناة %2$s + %1$s أرسل رسالة صوتية للقناة %2$s %1$s قام بإرسال ملصق للقناة %2$s %1$s أرسل رسالة %1$s أرسل صورة @@ -180,6 +184,13 @@ %1$s قام بنشر صورة متحركة %1$s أرسل رسالة صوتية %1$s أرسل ملصق + من يستطيع إضافة أعضاء؟ + جميع الأعضاء + فقط المشرفون + سيتم إشعار الأعضاء عند إرسال الرسائل. + لن يتم إشعار الأعضاء عند إرسال الرسائل. + وقّع الرسائل + قم بإضافة أسماء المشرفين للرسائل التي يرسلونها. رسالة جماعية جديدة أدخل اسم القائمة @@ -211,11 +222,11 @@ جاري الكتابة… يكتب… يكتبون… - %1$s يقوم بإرسال مقطع صوتي... + %1$s يقوم بتسجيل رسالة صوتية... %1$s يقوم بإرسال صورة... %1$s يقوم بإرسال مقطع مرئي... %1$s يقوم بإرسال ملف... - جاري تسجيل المقطع الصوتي... + جاري تسجيل الرسالة الصوتية... جاري إرسال الصورة... جاري إرسال المقطع المرئي... جاري إرسال الملف... @@ -284,7 +295,7 @@ %1$s قام بإرسال موقع لك %1$s قام بإرسال ملف لك %1$s أرسل لك صورة متحركة - %1$s قام بإرسال مقطع صوتي لك + %1$s قام بإرسال رسالة صوتية %1$s قام بإرسال ملصق %1$s @ %2$s: %3$s %1$s قام بإرسال رسالة للمجموعة %2$s @@ -294,7 +305,7 @@ %1$s قام بإرسال موقع للمجموعة %2$s %1$s قام بإرسال ملف للمجموعة %2$s %1$s أرسل صورة متحركة للمجموعة %2$s - %1$s قام بإرسال مقطع صوتي للمجموعة %2$s + %1$s أرسل رسالة صوتية للمجموعة %2$s %1$s قام بإرسال ملصق للمجموعة %2$s %1$s قام بدعوتك للمجموعة %2$s %1$s قام بتعديل اسم المجموعة %2$s @@ -331,6 +342,7 @@ رسالة جديدة إرسال الرسالة إلى... + ستتمكن من إضافة أعضاء أكثر إذا انتهيت من إنشاء المجموعة وقمت بتحويلها إلى مجموعة خارقة. أدخل اسم للمجموعة اسم المجموعة %1$d/%2$d عضو @@ -380,7 +392,8 @@ مفتاح التشفير عداد التدمير الذاتي إيقاف - هذه الصورة هي تصور لمفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
]]>إذا كانت مطابقة للصورة التي في جهاز ]]>%2$s]]>, فمحادثتكم آمنة ٢٠٠٪.
]]>للمزيد نرجو الذهاب إلى telegram.org
+ هذه الصورة والنص تم اشتقاقهم من مفتاح التشفير لهذه المحادثة السرية مع ]]>%1$s]]>.
]]>إذا كانت مطابقة لما يظهر على جهاز ]]>%2$s]]> ، التشفير من البداية للنهاية مضمون.
]]>للإستزادة، إطلع على telegram.org
+ https://telegram.org/faq#secret-chats غير معروف معلومات هاتف @@ -411,6 +424,7 @@ نسخ الرابط حذف لا يوجد ملصقات بعد + المعذرة، لقد وصلت الحد الأعلى لحزم الملصقات. تم تعيين كافة الإشعارات افتراضيا حجم نص الرسائل @@ -477,6 +491,7 @@ عند تواجدك خارج البلاد لا يوجد وسائط تشغيل تلقائي للصور المتحركة + ارفع الجهاز للتحدث حفظ في الجهاز تعديل الاسم الأولوية @@ -507,6 +522,8 @@ الأوقات خلال دقائق + معاينة الرابط + المحادثات السرية إعدادات الذاكرة المخبئية قاعدة البيانات على الجهاز @@ -606,6 +623,15 @@ الظل الحبوب زيادة الحدة + تلاشي + تظليل + الظلال + الإضاءات + المنحنيات + الكل + أحمر + أخضر + أزرق الطمس إيقاف طولي @@ -620,6 +646,7 @@ أضف تعليق... تعليق الصورة تعليق المقطع المرئي + تعليق التحقق بخطوتين تعيين كلمة مرور إضافية @@ -702,6 +729,18 @@ المعذرة، يوجد الكثير من الطلبات حاليًا. لا نستطيع تغيير إعدادات الخصوصية الآن، يرجى الإنتظار. قم بتسجيل الخروج من جميع الأجهزة الأخرى باستثناء هذا الجهاز إضغط بإستمرار على المستخدم لحذفه + المجموعات + من يستطيع إضافتي للمجموعات؟ + بإمكانك تحديد من يستطيع إضافتك للمجموعات والقنوات كيفما تشاء. + دائمًا اسمح + لا تسمح أبدًا + دائمًا اسمح... + لا تسمح أبدًا... + هؤلاء المستخدمين يمكنهم أو لا يمكنهم إضافتك للمجموعات والقنوات بغض النظر عن الأعدادات أعلاه. + غيّر من يستطيع إضافتك للمجموعات والقنوات. + المعذرة، لا يمكنك إضافة هذا المستخدم للمجموعات بسبب إعدادات الخصوصية المتعلقة به. + المعذرة، لا يمكنك إضافة هذا المستخدم للقنوات بسبب إعدادات الخصوصية المتعلقة به. + المعذرة، لا يمكنك إنشاء مجموعة مع هؤلاء المستخدمين نظرًا لإعدادات الخصوصية المتعلقة بهم. تحرير الفيديو الفيديو الأصلي @@ -748,14 +787,14 @@ لقد قمت بالدخول للمجموعة باستخدام رابط الدعوة un1 قام بالدخول للمجموعة باستخدام رابط الدعوة un1 أزال un2 - غادر المجموعة العضو un1 + un1 غادر المجموعة un1 قام بإضافة un2 تمت إزالة صورة المجموعة من قِبَل un1 تم تغيير صورة المجموعة من قِبَل un1 un1 قام بتغيير اسم المجموعة إلى un2 تم إنشاء مجموعة جديدة من قِبَل un1 لقد قمت بإخراج un2 - لقد قمت بمغادرة المجموعة + أنت غادرت المجموعة لقد قمت بإضافة un2 لقد قمت بإزالة صورة المجموعة لقد قمت بتغيير صورة المجموعة @@ -765,7 +804,7 @@ un1 قام بإضافتك un1 عاد إلى المجموعة لقد عدت إلى المجموعة - نسخة تيليجرام الموجودة لديك لا تدعم هذه الرسالة. الرجاء التحديث لأحدث نسخة لاستعراضها: https://telegram.org/update + نسخة تيليجرام الموجودة لديك لا تدعم هذه الرسالة. الرجاء التحديث لأحدث نسخة: https://telegram.org/update صورة مقطع مرئي صورة متحركة @@ -773,7 +812,7 @@ جهة اتصال ملف ملصق - مقطع صوتي + رسالة صوتية أنت أنت أخذت لقطة للشاشة ! un1 أخذ لقطة للشاشة ! @@ -818,6 +857,10 @@ .Sorry, this feature is currently not available in your country لا يوجد حساب تيليجرام بهذا الاسم. هذا البوت لا يستطيع الدخول للمجموعات. + هل ترغب في تفعيل معاينة الروابط المطولة في المحادثات السرية؟ تذكر أن هذه المعاينات يتم إنشاؤها في خوادم تيليجرام. + يرجى ملاحظة أن البوتات أثناء الكتابة يتم تطويرها من مطورين مستقلين. لكي تعمل هذه البوتات، ما تكتبه بعد معرف البوت يذهب لمطور البوت. + هل ترغب في تفعيل خاصية رفع الجهاز لإرسال الرسائل الصوتية؟ + المعذرة، لا يمكنك التعديل على هذه الرسالة. تيليجرام يحتاج للسماح له بالوصول لجهات الاتصال الخاصة بك لتتمكن من محادثة أصدقائك من كافة أجهزتك. تيليجرام يحتاج للسماح له بالوصول للذاكرة الخاصة بك لتتمكن من إرسال وحفظ الصور، المقاطع المرئية، الموسيقى وغيرها من الوسائط. @@ -998,12 +1041,18 @@ %1$d مقطع مرئي معاد توجيهه %1$d مقطع مرئي معاد توجيهه %1$d مقطع مرئي معاد توجيهه - %1$d مقطع صوتي معاد توجيهه - مقطع صوتي معاد توجيهه - %1$d مقطع صوتي معاد توجيهه - %1$d مقطع صوتي معاد توجيهه - %1$d مقطع صوتي معاد توجيهه - %1$d مقطع صوتي معاد توجيهه + %1$d مقاطع صوتية معاد إرسالها + مقاطع صوتية معاد إرسالها + %1$d مقاطع صوتية معاد إرسالها + %1$d مقاطع صوتية معاد إرسالها + %1$d مقاطع صوتية معاد إرسالها + %1$d مقاطع صوتية معاد إرسالها + %1$d رسالة صوتية معاد توجيهها + رسالة صوتية معاد توجيهها + %1$d رسالة صوتية معاد توجيهها + %1$d رسالة صوتية معاد توجيهها + %1$d رسالة صوتية معاد توجيهها + %1$d رسالة صوتية معاد توجيهها %1$d موقع معاد توجيهه موقع معاد توجيهه %1$d موقع معاد توجيهه @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s الساعة %2$s - - تيليجرام نسخة الأندرويد تم تحديثه. الجديد في نسخة 3.4.0:\n\nثورة الصور المتحركة: صور متحركة أسرع بعشر أضعاف في الإرسال والتنزيل، تشغيل تلقائي، حفظ صورك المفضلة في قسم خاص مع الملصقات.\n\nللاستزادة عن الصور المتحركة:\nhttps://telegram.org/blog/gif-revolution\n\nالبوت أثناء الكتابة: طريقة جديدة لإضافة محتوى البوت لأي محادثة. اكتب معرف البوت ثم نص البحث بعده لتحصل على نتائج فورية لإرسالها. جرب كتابة @gif ثم أي كلمة بعدها. البوتات التجريبية حاليًا هي: @gif و @wiki و @bing و @vid و @bold .\n\nللاستزادة عن البوتات أثناء الكتابة، من هنا:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 415122466..7868b705f 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -90,6 +90,7 @@ Wenn du Kommentare aktivierst, können sich alle an der Diskussion beteiligen. Kontakte zum Kanal hinzufügen Jeder kann diesen Link teilen und deinen Kanal in der Telegramsuche finden. + Link Alle Telegramnutzer können mit diesem Link deinem Kanal beitreten, du kannst ihn aber jederzeit widerrufen. Beschreibung @@ -117,6 +118,8 @@ Kanalnamen benötigen mindestens 5 Zeichen. Der Name darf maximal 32 Zeichen haben. Kanalnamen dürfen nicht mit einer Zahl anfangen. + + Überprüfe Namen... %1$s ist verfügbar. Mitglieder @@ -128,6 +131,7 @@ Möchtest du wirklich diesen Kanal verlassen? Du verlierst dadurch alle Nachrichten des Kanals. Bearbeiten + Wenn du einen öffentlichen Link für deinen Kanal festlegst, kann ihn jeder über die Suche finden und beitreten.\n\nWenn du das nicht möchtest, erstelle besser keinen Link. Bitte wähle einen Link für deinen öffentlichen Kanal, damit andere ihn finden und weiter verbreiten können.\n\nWenn du das nicht möchtest, empfehlen wir dir einen privaten Kanal. Kanal erstellt @@ -180,6 +184,13 @@ %1$s hat ein GIF gesendet %1$s hat eine Sprachnachricht gesendet %1$s hat einen Sticker gesendet + Wer kann Mitglieder einladen? + Alle Mitglieder + Nur Admins + Mitglieder werden benachrichtigt + Mitglieder werden nicht benachrichtigt + Nachrichten unterschreiben + Zeigt für neue Nachrichten an, welcher Admin die Nachricht gesendet hat. Neue Broadcast Liste Listenname @@ -284,7 +295,7 @@ %1$s hat dir einen Standort gesendet %1$s hat dir eine Datei gesendet %1$s hat dir ein GIF gesendet - %1$s hat dir eine Audio-Datei gesendet + %1$s hat dir eine Sprachnachricht gesendet %1$s hat dir einen Sticker gesendet %1$s @ %2$s: %3$s %1$s hat eine Nachricht an die Gruppe %2$s gesendet @@ -294,7 +305,7 @@ %1$s hat einen Standort an die Gruppe %2$s gesendet %1$s hat eine Datei an die Gruppe %2$s gesendet %1$s hat ein GIF an die Gruppe %2$s gesendet - %1$s hat eine Audio-Datei an die Gruppe %2$s gesendet + %1$s hat eine Sprachnachricht an die Gruppe %2$s gesendet %1$s hat einen Sticker an die Gruppe %2$s gesendet %1$s hat dich in die Gruppe %2$s eingeladen %1$s hat den Namen der Gruppe %2$s geändert @@ -331,6 +342,7 @@ Neue Nachricht Sende Nachricht an… + Sobald du diese Gruppe zu einer Supergruppe erweitert hast, kannst du mehr Nutzer einladen. Gruppenname Gruppenname %1$d/%2$d Mitglieder @@ -380,7 +392,8 @@ Geheimer Schlüssel Selbstzerstörungs-Timer Aus - Die Abbildung zeigt den aktuellen Schlüssel dieses geheimen Chats mit ]]>%1$s]]>.
]]>Wenn dieses Bild auf dem Gerät von ]]>%2$s]]> genau so aussieht, ist euer Chat zu 200%% sicher.
]]>Erfahre mehr auf telegram.org
+ Bild und Text zeigen den aktuellen Schlüssen dieses geheimen Chats mit ]]>%1$s]]>.
]]>Sehen sie auf dem Gerät von ]]>%2$s]]> genau so aus, ist eure Sicherheit garantiert.
]]>Erfahre mehr unter telegram.org
+ https://telegram.org/faq/de#geheime-chats Unbekannt Info Telefon @@ -411,6 +424,7 @@ Link kopieren Entfernen Noch keine Sticker + Leider hast du die maximale Anzahl an Stickerpaketen erreicht. Alle Einstellungen für Mitteilungen zurücksetzen Textgröße für Nachrichten @@ -477,6 +491,7 @@ Bei Roaming kein automatischer Download GIFs autom. Abspielen + Zum Sprechen ans Ohr In der Galerie speichern Name bearbeiten Priorität @@ -507,11 +522,13 @@ Mal innerhalb von Minuten + Linkvorschau + Geheime Chats Cache-Einstellungen Lokale Datenbank Textnachrichten-Cache leeren? - Zwischengespeicherte Textnachrichten werden entfernt und die Datenbank optimiert um Speicherplatz zurückzuerhalten. Auf Null lässt sich die Größe jedoch nicht reduzieren, da die App einige Daten für den laufenden Betrieb benötigt.\n\n\Hinweis: Der Vorgang kann mehrere Minuten dauern. + Zwischengespeicherte Textnachrichten werden entfernt und die Datenbank optimiert um Speicherplatz zurückzuerhalten. Auf Null lässt sich die Größe jedoch nicht reduzieren, da die App einige Daten für den laufenden Betrieb benötigt.\n\nHinweis: Der Vorgang kann mehrere Minuten dauern. Cache Leeren Leeren Berechne... @@ -597,7 +614,7 @@ Bild zuschneiden Bild bearbeiten Verbessern - Highlights + Lichter Kontrast Belichtung Wärme @@ -606,6 +623,15 @@ Schatten Körnung Schärfe + Verblassen + Tönung + TIEFEN + LICHTER + Kurven + ALLE + ROT + GRÜN + BLAU Unschärfe Aus Linear @@ -620,6 +646,7 @@ Beschriftung... Bildbeschriftung Videobeschriftung + Beschriftung Zweistufige Bestätigung Zusätzliches Kennwort festlegen @@ -702,6 +729,18 @@ Du hast zu oft probiert, deine Einstellungen zu ändern; bitte warte kurz. Alle Geräte außer diesem werden abgemeldet. Auf Nutzer tippen und halten um zu löschen. + Gruppen + Wer kann mich in Gruppen einladen? + Du kannst bestimmen, wer dich in Gruppen oder Kanäle einladen darf. + Immer erlauben + Niemals erlauben + Immer erlauben... + Niemals erlauben... + Hier kannst du Nutzer hinzufügen, für die eine Ausnahme gemacht werden soll. + Ändere, wer dich in Gruppen und Kanäle einladen kann. + Du kannst diesen Nutzer nicht hinzufügen, weil er das nicht erlaubt. + Du kannst diesen Nutzer nicht hinzufügen, weil er das nicht erlaubt. + Du kannst mit diesen Nutzern keine Gruppe erstellen, weil sie es nicht erlauben. Video bearbeiten Originalvideo @@ -773,7 +812,7 @@ Kontakt Datei Sticker - Audio + Sprachnachricht Du Du hast ein Bildschirmfoto gemacht! un1 hat ein Bildschirmfoto gemacht! @@ -818,6 +857,10 @@ Verzeihung, diese Funktion ist derzeit in deinem Land nicht verfügbar. Kein Konto mit diesem Benutzernamen Keine Gruppen mit diesem Bot möglich + Möchtest du die erweitere Linkvorschau in Geheimen Chats aktivieren? Die Vorschau wird auf den Telegram Servern generiert. + Inline Bots werden von Drittentwicklern erstellt. Symbole, die du nach dem Botnamen eingibst, werden an den jeweiligen Entwickler geschickt, damit der Bot funktioniert. + Möchtest du \"Zum Sprechen ans Ohr\" für Sprachnachrichten aktivieren? + Du kannst diese Nachricht nicht bearbeiten. Telegram benötigt Zugriff auf deine Kontakte um dich auf all denen Geräten mit deinen Freunden zu verbinden. Telegram benötigt Zugriff auf deinen Speicher, damit du Bilder, Videos und Musik senden und speichern kannst. @@ -854,7 +897,7 @@ %1$d Mitglieder %1$d Mitglieder und %1$d weitere schreiben - und %1$d weitere schreiben + und %1$d weitere tippen und %1$d weitere schreiben und %1$d weitere schreiben und %1$d weitere schreiben @@ -998,12 +1041,18 @@ %1$d angehängte Videos %1$d angehängte Videos %1$d angehängte Videos - %1$d angehängten Audios - Angehängtes Audio - %1$d angehängte Audios - %1$d angehängte Audios - %1$d angehängte Audios - %1$d angehängte Audios + %1$d angehängte Musikstücke + Angehängtes Musikstück + %1$d angehängte Musikstücke + %1$d angehängte Musikstücke + %1$d angehängte Musikstücke + %1$d angehängte Musikstücke + %1$d weitergeleitete Sprachnachrichten + Weitergeleitete Sprachnachricht + %1$d weitergeleitete Sprachnachrichten + %1$d weitergeleitete Sprachnachrichten + %1$d weitergeleitete Sprachnachrichten + %1$d weitergeleitete Sprachnachrichten %1$d weitergeleiteten Standorte Angehängter Standort %1$d angehängte Standorte @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s um %2$s - - Telegram für Android wurde aktualisiert. Neu in Version 3.4.0:\n\nGIF-Revolution: GIFs bis zu 20x schneller senden und empfangen, GIF-Autoplay und GIF-Speicherung im Sticker-Panel.\n\nMehr über die neuen GIFs:\nhttps://telegram.org/blog/gif-revolution\n\nInline-Bots: Binde Inhalte der neuen Inline-Bots in alle Chats noch einfacher ein. Probiere mal "@gif dog" im Texteingabefeld aus. Beispiel-Bots: @gif, @wiki, @bing @vid und @bold.\n\nInfos zu Inline-Bots\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 62b0ec4f8..74d816424 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -90,6 +90,7 @@ Si activas los comentarios, las personas podrán hablar de tus mensajes en el canal. Añadir contactos a tu canal Las personas pueden compartir este enlace con los demás y encontrar tu canal usando la búsqueda de Telegram. + Enlace Las personas pueden unirse a tu canal siguiendo este enlace. Puedes anular el enlace en cualquier momento. Descripción @@ -117,6 +118,8 @@ El nombre del canal debe tener al menos 5 caracteres. El nombre no debe exceder los 32 caracteres. El nombre del canal no puede comenzar con un número. + + Verificando nombre... %1$s está disponible. Miembros @@ -128,6 +131,7 @@ ¿Quieres dejar este canal? Perderás todos los mensajes en este canal. Editar + Por favor, ten en cuenta que si eliges un enlace público para tu canal, cualquiera podrá encontrarlo en la búsqueda y unirse.\n\nNo crees este enlace si quieres que tu canal sea privado. Por favor, elige un enlace para tu canal público. Así, las personas podrán encontrarlo en la búsqueda y compartirlo con otros.\n\nSi no estás interesado, te sugerimos crear un canal privado. Canal creado @@ -169,7 +173,7 @@ %1$s envió una ubicación al canal %2$s %1$s envió un archivo al canal %2$s %1$s envió un GIF al canal %2$s - %1$s envió un audio al canal %2$s + %1$s envió un mensaje de voz al canal %2$s %1$s envió un sticker al canal %2$s %1$s publicó un mensaje %1$s publicó una foto @@ -180,6 +184,13 @@ %1$s publicó un GIF %1$s publicó un mensaje de voz %1$s publicó un sticker + ¿Quién puede invitar? + Todos + Administradores + Tu publicación será notificada + Tu publicación no será notificada + Firmar los mensajes + Añadir los nombres de los administradores a sus publicaciones. Nueva difusión Nombre de la lista @@ -211,11 +222,11 @@ escribiendo... está escribiendo... están escribiendo... - %1$s está grabando un audio... + %1$s está grabando un mensaje de voz... %1$s está enviando una foto... %1$s está enviando un vídeo... %1$s está enviando un archivo... - grabando audio... + grabando mensaje de voz... enviando foto... enviando vídeo... enviando archivo... @@ -284,7 +295,7 @@ %1$s te envió una ubicación %1$s te envió un archivo %1$s te envió un GIF - %1$s te envió un audio + %1$s te envió un mensaje de voz %1$s te envió un sticker %1$s @ %2$s: %3$s %1$s envió un mensaje al grupo %2$s @@ -294,7 +305,7 @@ %1$s envió una ubicación al grupo %2$s %1$s envió un archivo al grupo %2$s %1$s envió un GIF al grupo %2$s - %1$s envió un audio al grupo %2$s + %1$s envió un mensaje de voz al grupo %2$s %1$s envió un sticker al grupo %2$s %1$s te invitó al grupo %2$s %1$s cambió el nombre del grupo %2$s @@ -331,6 +342,7 @@ Nuevo mensaje Invitar a... + Podrás añadir más usuarios después de crear el grupo y convertirlo en un supergrupo. Nombre del grupo Nombre del grupo %1$d/%2$d miembros @@ -380,7 +392,8 @@ Clave de cifrado Autodestrucción Apagada - Esta imagen es una visualización de la clave de cifrado para el chat secreto con ]]>%1$s]]>.
]]>Si esta imagen se ve igual en el teléfono de ]]>%2$s]]>, tu chat es seguro en un 200%%.
]]>Aprende más en telegram.org
+ El texto e imagen derivan de la clave de cifrado para el chat secreto creado con ]]>%1$s]]>.
]]>Si se ven igual en el dispositivo de ]]>%2$s]]>, el cifrado end-to-end está garantizado.
]]>Conoce más en telegram.org
+ https://telegram.org/faq/es#chats-secretos Desconocido Información Teléfono @@ -411,6 +424,7 @@ Copiar enlace Eliminar Sin stickers aún + Lo sentimos, alcanzaste el número máximo de packs de stickers. Restablecer las notificaciones Tamaño del texto @@ -477,6 +491,7 @@ Con itinerancia de datos Ningún contenido multimedia Autorreproducción de GIF + Elevar para hablar Guardar en galería Editar nombre Prioridad @@ -507,6 +522,8 @@ veces en minutos + Vistas previas de enlaces + Chats secretos Ajustes de caché Base de datos local @@ -606,6 +623,15 @@ Sombras Grano Nitidez + Desvanecer + Matiz + SOMBRAS + ILUMINACIÓN + Curvas + TODO + ROJO + VERDE + AZUL Desenfoque Apagado Lineal @@ -620,6 +646,7 @@ Añadir un comentario... Comentario de foto Comentario de vídeo + Comentario Verificación en dos pasos Poner contraseña adicional @@ -702,6 +729,18 @@ Lo sentimos, hay demasiadas solicitudes. Es imposible cambiar los ajustes de privacidad ahora. Por favor, espera. Salir de todos los dispositivos, excepto este. Mantén pulsado sobre un usuario para eliminarlo. + Grupos + ¿Quién puede añadirme a grupos? + Puedes restringir quién puede añadirte a grupos o canales con gran precisión. + Permitir + No permitir + Permitir... + No permitir... + Estos usuarios podrán o no añadirte a grupos y canales, independiente de los ajustes de arriba. + Cambia quiénes pueden añadirte a grupos o canales. + No puedes añadir este usuario a grupos debido a sus ajustes de privacidad. + No puedes añadir este usuario a canales debido a sus ajustes de privacidad. + No puedes crear un grupo con estos usuarios debido a sus ajustes de privacidad. Editar vídeo Vídeo original @@ -765,7 +804,7 @@ un1 te añadió un1 volvió al grupo Volviste al grupo - Este mensaje no está soportado en tu versión de Telegram. Actualiza la aplicación para verlo: https://telegram.org/update + Tu versión de Telegram no soporta este mensaje. Por favor, actualiza tu app para verlo: https://telegram.org/update Foto Vídeo GIF @@ -773,7 +812,7 @@ Contacto Archivo Sticker - Audio + Mensaje de voz ¡Hiciste una captura de pantalla! ¡un1 hizo una captura de pantalla! @@ -818,6 +857,10 @@ Lo sentimos, esta característica no está disponible en tu país actualmente. No hay ninguna cuenta de Telegram con este alias. Este bot no puede unirse a grupos. + ¿Quieres permitir las vistas previas ampliadas en chats secretos? Ten en cuenta que son generadas en los servidores de Telegram. + Ten en cuenta que los bots integrados son hechos por terceros. Para que funcione, los símbolos escritos después del alias del bot, son enviados al desarrollador respectivo. + ¿Quieres habilitar \"Elevar para hablar\" para mensajes de voz? + No puedes editar este mensaje. Telegram necesita el acceso a tus contactos, para que puedas comunicarte con ellos en todos tus dispositivos. Telegram necesita acceso a tu almacenamiento, para que puedas enviar y guardar fotos, vídeos, música y otros archivos. @@ -854,7 +897,7 @@ %1$d miembros %1$d miembros y %1$d personas más están escribiendo - y %1$d persona más están escribiendo + y %1$d más están escribiendo y %1$d personas más están escribiendo y %1$d personas más están escribiendo y %1$d personas más están escribiendo @@ -998,12 +1041,18 @@ %1$d vídeos adjuntos %1$d vídeos adjuntos %1$d vídeos adjuntos - %1$d audios adjuntos - Audio adjunto - %1$d audios adjuntos - %1$d audios adjuntos - %1$d audios adjuntos - %1$d audios adjuntos + %1$d pistas reenviadas + Pista reenviada + %1$d pistas reenviadas + %1$d pistas reenviadas + %1$d pistas reenviadas + %1$d pistas reenviadas + %1$d mensajes de voz reenviados + Mensaje de voz reenviado + %1$d mensajes de voz reenviados + %1$d mensajes de voz reenviados + %1$d mensajes de voz reenviados + %1$d mensajes de voz reenviados %1$d ubicaciones adjuntas Ubicación adjunta %1$d ubicaciones adjuntas @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s a las %2$s - - Telegram para Android ha sido actualizada. Novedades en la versión 3.4.0:\n\nRevolución GIF: envío y descarga 20 veces más rápido, autorreproducción, guarda tus GIF en el panel de stickers.\n\nMás sobre los GIF:\nhttps://telegram.org/blog/gif-revolution\n\nBots integrados: una nueva forma de enviar contenidos en los chats. Escribe el alias del bot y tu solicitud, en el campo de escritura, y obtén resultados inmediatamente. Prueba escribiendo "@gif perro" en un chat. Algunos ejemplos: @gif, @wiki, @bing, @vid, @bold.\n\nMás sobre los bots integrados:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 39931c18f..bcae59fba 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -90,6 +90,7 @@ Se attivi i commenti, i membri potranno discutere quello che pubblichi nel canale. Aggiungi contatti al tuo canale Le persone possono condividere questo link con gli altri e trovare il tuo canale usando la ricerca di Telegram. + link Le persone possono unirsi al tuo canale tramite questo link. Puoi revocare il link in ogni momento. Descrizione @@ -117,6 +118,8 @@ I nomi devi canali devono avere almeno 5 caratteri. Il nome non può superare i 32 caratteri. I nomi dei canali non possono iniziare con un numero. + + Controllo il nome... %1$s è disponibile. Membri @@ -128,6 +131,7 @@ Sei sicuro di voler lasciare il canale? Perderai tutti i messaggi in questo canale. Modifica + Per favore ricorda che se scegli un link pubblico per il tuo canale, chiunque sarà in grado di trovarlo nella ricerca e unirsi.\n\nNon creare questo link se vuoi che il tuo canale rimanga privato. Per favore scegli un link per il tuo canale pubblico, in modo che possa essere trovato nella ricerca e condiviso con altri.\n\nSe non sei interessato, ti consigliamo di creare un canale privato. Canale creato @@ -169,7 +173,7 @@ %1$s ha inviato una posizione al canale %2$s %1$s ha inviato un file al canale %2$s %1$s ha inviato una GIF al canale %2$s - %1$s ha inviato un audio al canale %2$s + %1$s ha inviato un messaggio vocale al canale %2$s %1$s ha inviato uno sticker al canale %2$s %1$s ha pubblicato un messaggio %1$s ha pubblicato una foto @@ -180,6 +184,13 @@ %1$s ha pubblicato una GIF %1$s ha pubblicato un messaggio vocale %1$s ha pubblicato uno sticker + Chi può aggiungere nuovi membri? + Tutti i membri + Solo gli amministratori + Notifica i membri quando pubblichi + Non notifica i membri quando pubblichi + Firma messaggi + Aggiungi i nomi degli amministratori nei messaggi che pubblicano. Nuova lista broadcast Inserisci il nome della lista @@ -211,11 +222,11 @@ sta scrivendo… sta scrivendo… stanno scrivendo… - %1$s sta registrando un audio... + %1$s sta registrando un messaggio vocale... %1$s sta inviando una foto... %1$s sta inviando un video... %1$s sta inviando un file... - registrando un audio... + registrando un messaggio vocale... inviando una foto... inviando un video... inviando un file... @@ -284,7 +295,7 @@ %1$s ti ha inviato una posizione %1$s ti ha inviato un file %1$s ti ha inviato una GIF - %1$s ti ha inviato un audio + %1$s ti ha inviato un messaggio vocale %1$s ti ha inviato uno sticker %1$s @ %2$s: %3$s %1$s ha inviato un messaggio al gruppo %2$s @@ -294,7 +305,7 @@ %1$s ha inviato una posizione al gruppo %2$s %1$s ha inviato un file al gruppo %2$s %1$s ha inviato una GIF al gruppo %2$s - %1$s ha inviato un audio al gruppo %2$s + %1$s ha inviato un messaggio vocale al gruppo %2$s %1$s ha inviato uno sticker al gruppo %2$s %1$s ti ha invitato nel gruppo %2$s %1$s ha modificato il nome del gruppo %2$s @@ -331,6 +342,7 @@ Nuovo messaggio Invia messaggio a... + Sarai in grado di aggiungere più utenti dopo aver creato il gruppo e averlo convertito in supergruppo. Immetti il nome del gruppo Nome gruppo %1$d/%2$d membri @@ -380,7 +392,8 @@ Chiave di cifratura Timer di autodistruzione Spento - Questa immagine è una visualizzazione della chiave di cifratura per questa chat segreta con ]]>%1$s]]>.
]]>Se questa immagine è uguale sul telefono di ]]>%2$s]]>, la chat è sicura al 200%%.
]]>Per saperne di più, visita Telegram.org
+ Questa immagine e il testo sono derivati dalla chiave di crittografia per questa chat segreta con ]]>%1$s]]>.
]]>Se sono uguali sul dispositivo di ]]>%2$s]]>, la crittografia end-to-end è garantita.
]]>Ulteriori informazioni su telegram.org
+ https://telegram.org/faq#secret-chats Sconosciuto Info Telefono @@ -411,6 +424,7 @@ Copia link Rimuovi Ancora nessuno sticker + Spiacenti, hai raggiunto il numero massimo di set di sticker. Ripristina tutte le impostazioni di notifica predefinite Dimensione testo messaggi @@ -477,6 +491,7 @@ In roaming Nessun media Autoriproduzione GIF + Alza per parlare Salva nella galleria Modifica nome Priorità @@ -507,6 +522,8 @@ volte in minuti + Anteprime link + Chat segrete Impostazioni cache Database locale @@ -517,7 +534,7 @@ Calcolando... Documenti Foto - Note vocali + Messaggi vocali Video Musica Altri file @@ -606,6 +623,15 @@ Ombre Grana Nitidezza + Sfumatura + Colore + OMBRE + ALTE LUCI + Curve + TUTTO + ROSSO + VERDE + BLU Sfocatura No Lineare @@ -620,6 +646,7 @@ Aggiungi una didascalia... Didascalia foto Didascalia video + Didascalia Verifica in due passaggi Imposta password aggiuntiva @@ -702,6 +729,18 @@ Spiacenti, troppe richieste. Impossibile cambiare le impostazioni di privacy ora, attendi. Disconnette tutti i dispositivi tranne questo. Tieni premuto sull\'utente per eliminarlo. + Gruppo + Chi può aggiungermi ai gruppi? + Puoi decidere chi può aggiungerti a gruppi e canali con precisione granulare. + Consenti sempre + Non consentire mai + Consenti sempre... + Non consentire mai... + Questi utenti saranno o non saranno in grado di aggiungerti a gruppi e canali indipendentemente dalle impostazioni precedenti. + Cambia chi può aggiungerti a gruppi e canali. + Spiacenti, non puoi aggiungere questo utente al gruppo a causa delle sue impostazioni di privacy. + Spiacenti, non puoi aggiungere questo utente al canale a causa delle sue impostazioni di privacy. + Spiacenti, non puoi creare un gruppo con questi utenti a causa delle loro impostazioni di privacy. Modifica video Video originale @@ -765,7 +804,7 @@ un1 ti ha aggiunto un1 è tornato nel gruppo Sei tornato nel gruppo - Questo messaggio non è supportato sulla tua versione di Telegram. Aggiorna l\'applicazione per visualizzarlo: https://telegram.org/update + Questo messaggio non è supportato dalla tua versione di Telegram. Aggiorna l\'app per visualizzarlo: https://telegram.org/update Foto Video GIF @@ -773,7 +812,7 @@ Contatto File Sticker - Audio + Messaggio vocale Tu Hai fatto uno screenshot! un1 ha fatto uno screenshot! @@ -818,6 +857,10 @@ Spiacenti, questa funzione non è disponibile nel tuo paese. Non esiste alcun account Telegram con questo username. Questo bot non può unirsi ai gruppi. + Vuoi attivare le anteprime estese per i link nelle Chat Segrete? Ricorda che le anteprime dei link sono generate sui server di Telegram. + Per favore ricorda che i bot inline sono forniti da sviluppatori di terze parti. Per far funzionare il bot, i simboli che digiti dopo l\'username del bot sono inviati al rispettivo sviluppatore. + Vuoi attivare \"Alza per parlare\" per i messaggi vocali? + Spiacenti, non puoi modificare questo messaggio. Telegram deve accedere ai tuoi contatti per poterti connettere con i tuoi amici su tutti i tuoi dispositivi. Telegram deve accedere alla tua memoria per poter inviare e salvare foto,video, musica e altri media. @@ -854,7 +897,7 @@ %1$d membri %1$d membri e %1$d altre persone stanno scrivendo - e %1$d altra persona stanno scrivendo + e %1$d altre persone stanno scrivendo e %1$d altre persone stanno scrivendo e %1$d altre persone stanno scrivendo e %1$d altre persone stanno scrivendo @@ -998,12 +1041,18 @@ %1$d video inoltrati %1$d video inoltrati %1$d video inoltrati - %1$d audio inoltrati - Audio inoltrato - %1$d audio inoltrati - %1$d audio inoltrati - %1$d audio inoltrati - %1$d audio inoltrati + %1$d tracce inoltrate + Traccia inoltrata + %1$d tracce inoltrate + %1$d tracce inoltrate + %1$d tracce inoltrate + %1$d tracce inoltrate + %1$d messaggi vocali inoltrati + Messaggio vocale inoltrato + %1$d messaggi vocali inoltrati + %1$d messaggi vocali inoltrati + %1$d messaggi vocali inoltrati + %1$d messaggi vocali inoltrati %1$d posizioni inoltrate Posizione inoltrata %1$d posizione inoltrate @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s alle %2$s - - Telegram per Android si è aggiornato. Nuovo nella versione 3.4.0:\n\nRivoluzione GIF: Invio e download 20 volte più veloci, autoriproduci e salva le tue preferite nel pannello sticker.\n\nPiù info sulle GIF:\nhttps://telegram.org/blog/gif-revolution\n\nBot Inline: Un nuovo modo di aggiungere contenuti in ogni chat. Menziona un bot e la tua domanda nel campo di scrittura e ottieni risultati immediati. Prova a scrivere “@gif dog” nella tua prossima chat. Bot di esempio: @gif, @wiki, @bing, @vid, @bold\n\nPiù info sui Bot Inline:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 0521ce101..12ce89add 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -90,6 +90,7 @@ 코멘트를 허용할 경우, 유저들이 회원님 글에 대하여 코멘트 등록이 가능합니다. 채널에 친구 추가 텔레그램 검색을 통하여 다른 유저들이 채널을 찾을 수 있습니다. + 링크 이 링크를 통하여 다른 유저들이 채널에 입장 할 수 있습니다. 이 링크는 언제든지 폐기 가능합니다. 설명 @@ -117,6 +118,8 @@ 채널명은 최소 5 글자 이상 입력해야 합니다. 이름은 최대 32자까지만 가능합니다. 채널명은 숫자로 시작 할 수 없습니다. + + 이름 확인 중.. %1$s은 사용 가능합니다. 구성원 @@ -128,6 +131,7 @@ 채널에서 나가시겠습니까? 채널에 있는 모든 메시지가 삭제됩니다. 편집 + 채널에 대한 공개링크를 선택하신 경우, 누구나 검색을 통하여 입장 가능합니다.\n\n비공개 채널로 유지를 하시고 싶으실 경우 링크 생성을 하지 말아주세요 유저들이 공개 채널에 대하여 검색 및 공유가 가능하도록 링크를 선택하여 주세요.\n\n채널을 공개하시지 싫으실 경우, 비공개 채널을 추천드립니다. 채널 생성됨 @@ -169,7 +173,7 @@ %1$s님이 %2$s 채널에 위치를 보냈습니다 %1$s님이 %2$s 채널에 파일을 보냈습니다 %1$s님이 %2$s 채널에 GIF파일을 보냈습니다 - %1$s님이 %2$s 채널에 오디오를 보냈습니다 + %1$s님이 %2$s 채널에 음성메시지를 보냈습니다 %1$s님이 %2$s 채널에 스티커를 보냈습니다 %1$s 님이 메시지를 보냈습니다 %1$s 님이 사진을 보냈습니다 @@ -180,6 +184,13 @@ %1$s 님이 GIF파일을 보냈습니다 %1$s님이 음성메시지를 보냈습니다 %1$s님이 스티커를 보냈습니다 + 초대가 가능한 구성원 + 모든 구성원 + 관리자만 가능 + 메시지 알림 대상 + 메시지 미알림 대상 + 메시지 서명 + 메시지 작성하는 관리자 추가 새 단체 메시지 리스트 리스트 이름을 입력하세요 @@ -211,11 +222,11 @@ 입력 중... 님이 입력 중... 님이 입력 중... - %1$s님이 녹음 중... + %1$s님이 음성메시지를 녹음중입니다... %1$s님이 사진 보내는 중... %1$s님이 동영상 보내는 중... %1$s님이 파일 보내는 중... - 음성메시지 녹음 중... + 음성메시지를 녹음 중입니다.. 사진 전송 중.. 동영상 전송 중.. 파일 전송 중... @@ -331,6 +342,7 @@ 새 메시지 메시지 보내기... + 이 그룹 생성을 완료하시고 슈퍼그룹으로 전환하시면 더 많은 구성원을 추가 할 수 있습니다. 그룹 이름 입력 그룹 이름 대화상대 %1$d/%2$d @@ -380,7 +392,8 @@ 암호화 키 자동삭제 타이머 해제 - 이 이미지는 ]]>%1$s]]>님과의 비밀대화에 사용 중인 암호화 키의 모습입니다.
]]>이 이미지가 ]]>%2$s]]>님의 암호화 키와 똑같다면 대화는 200%% 안전합니다.
]]>더 자세한 사항은 telegram.org 를 참고해 주세요.
+ 이 이미지와 텍스트는 ]]>%1$s]]>.
]]> 님과의 현재 비밀대화에 대한 비밀키에서 파생된 것입니다. 이 이미지와 텍스트가 ]]>%2$s\'s]]> 님의 휴대전화와 동일하다면 단말기간(end-to-end)의 암호화가 정상적으로 진행되고 있음을 보장합니다.
]]> 자세한 사항은 telegram.org를 참고해 주세요.
+ https://telegram.org/faq#secret-chats 알 수 없음 정보 전화번호 @@ -411,6 +424,7 @@ 링크 복사 삭제 스티커가 아직 없음 + 죄송합니다, 스티커 세트수가 최대치입니다. 모든 알림 설정이 초기화되었습니다 채팅 글자 크기 @@ -477,6 +491,7 @@ 로밍 중일 때 다운로드 안함 GIF 자동재생 + 기기를 들어 말하기 앨범에 자동 저장 이름 편집 우선순위 @@ -507,6 +522,8 @@ 이내 + 링크 프리뷰 + 비밀대화 캐시 설정 로컬 데이터베이스 @@ -606,6 +623,15 @@ 그림자 그레인 선명 + 흐리기 + 색조 + 새도우 + 하이라이트 + 커브 + 모두 + 빨강 + 초록 + 파랑 흐림 선형 @@ -620,6 +646,7 @@ 설명 추가... 사진 설명 동영상 설명 + 설명 2단계 인증 개별 비밀번호 설정 @@ -632,7 +659,7 @@ 복구 이메일 이메일 올바른 이메일을 입력해주세요. 비밀번호 분실시 유일하게 복구가 가능한 수단입니다. - 건너뛱 + 건너뛰기 경고 비밀번호 분실시\n\n텔레그램에 대한 모든 접속 권한을 상실하시게 됩니다.\n비밀번호 분실시 복구는 불가능 합니다. 거의 마무리 되었습니다! @@ -702,6 +729,18 @@ 죄송합니다. 너무 많이 변경하셨습니다. 개인정보 설정을 변경할 수 없으니 잠시 기다려 주세요. 이 기기를 제외한 다른 기기에서 로그아웃합니다. 사용자를 탭하고 눌러서 삭제하세요. + 그룹 + 나를 그룹에 초대가능한 사용자 + 회원님을 그룹 및 채널에 초대할 수 있는 상대방을 세세하게 설정 가능합니다. + 항상 허용 + 항상 거부 + 항상 허용.. + 항상 거부.. + 위의 설정과 무관하게 해당 사용자는 회원님을 그룹 및 채널에 초대 할 수 없습니다. + 그룹 및 채널에 초대가능한 사용자 변경 + 죄송합니다, 이 이용자는 개인 설정으로 인하여 그룹에 초대 할 수 없습니다. + 죄송합니다, 이 이용자는 개인 설정으로 인하여 채널에 초대 할 수 없습니다. + 죄송합니다, 이 이용자들의 개인 설정으로 인하여 그룹을 생성 할 수 없습니다. 동영상 편집 동영상 원본 @@ -748,14 +787,14 @@ 초대링크를 타고 그룹에 참여하였습니다. 초대링크를 타고 그룹에 un1님이 참여하였습니다. un1님이 un2님을 퇴장시켰습니다. - un1님이 퇴장했습니다 + un1님이 그룹에서 나갔습니다. un1님이 un2님을 초대했습니다 un1님이 그룹 사진을 삭제했습니다 un1님이 그룹 사진을 변경했습니다 un1님이 그룹 이름을 un2 그룹으로 변경했습니다 un1님이 그룹을 만들었습니다 un2님을 퇴장시켰습니다. - 그룹을 떠났습니다 + 그룹에서 나갔습니다. un2님을 초대했습니다 그룹 사진을 삭제했습니다 그룹 사진을 변경했습니다 @@ -765,7 +804,7 @@ un1님이 그룹에 초대했습니다 un1 님께서 그룹에 돌아오셨습니다 그룹에 돌아오셨습니다. - 이 메시지는 현재 사용 중인 버전의 Telegram에서 지원되지 않습니다. 메시지를 보려면 https://telegram.org/update 에서 앱을 업데이트하세요. + 이 메시지는 현재 사용 중인 버전의 Telegram에서 지원되지 않습니다. 메시지를 보려면 http://telegram.org/update에서 앱을 업데이트하세요. 사진 동영상 GIF파일 @@ -773,7 +812,7 @@ 연락처 파일 스티커 - 음성메시지 + 음성 메시지 화면을 캡처했습니다! un1님이 화면을 캡처했습니다! @@ -818,6 +857,10 @@ 이 기능은 회원님의 국가에서는 사용할 수 없습니다. 입력된 아이디와 일치하는 텔레그램 계정이 없습니다. 이 봇은 그룹에 참여 할 수 없습니다. + 비밀대화에서 링크 미리보기를 활성화하시겠습니까? 링크 프리뷰는 텔레그램 서버에서 생성이 됩니다. + 인라인 봇은 제3자 개발자로 부터 제공이 됩니다. 봇이 작동을 하려면 봇의 아이디 및 뒤의 메시지가 담당 개발자에게 전송이 됩니다. + \"기기를 들어 말하기\"기능을 음성 메시지에 활성화 하시겠습니까? + 죄송합니다, 메시지 수정을 할 수 없습니다. Telegram은 여러 기기에서 친구와 메시지를 주고받을 수 있도록 회원님의 연락처 접근이 필요합니다. Telegram은 사진, 비디오, 음악 및 다양한 미디어를 공유 및 저장하기 위하여 스토리지 접근이 필요합니다. @@ -998,12 +1041,18 @@ %1$d 개의 전달된 비디오 %1$d 개의 전달된 비디오 %1$d 개의 전달된 비디오 - %1$d 개의 전달된 오디오 - 전달된 오디오 - %1$d 개의 전달된 오디오 - %1$d 개의 전달된 오디오 - %1$d 개의 전달된 오디오 - %1$d 개의 전달된 오디오 + %1$d개의 전달된 트랙 + 전달된 트랙 + %1$d개의 전달된 트랙 + %1$d 전달된 트랙% + %1$d 전달된 트랙 + %1$d 전달된 트랙 + %1$d 개의 전달된 메시지 + 전달된 음성메시지 + %1$d 개의 전달된 음성메시지 + %1$d 개의 전달된 음성메시지 + %1$d 개의 전달된 음성메시지 + %1$d 개의 전달된 음성 메시지 %1$d 개의 전달된 위치 전달된 위치 %1$d 개의 전달된 위치 @@ -1039,7 +1088,4 @@ HH:mm a h:mm %1$s %2$s - - 텔레그램 안드로이드 버전이 업데이트 되었습니다. 새로운 버전은 3.4.0 입니다:\n\nGIF 혁명: 10배 빠른 전송, 다운로드 및 자동재생이 가능하며, 스티커 패널에서 즐겨찾는 GIF를 저장가능\n\nGIF에 대한 자세한 정보:\nhttps://telegram.org/blog/gif-revolution\n\n@-봇 : 모든 대화에 봇 기능을 추가 할 수 있습니다. 봇 아이디를 입력란에 같이 입력해주시면 즉시 결과값을 확인 할 수 있습니다."@gif dog"와 같은 명령어를 입력란에 같이 입력해보세요. 예시:@gif, @wiki, @bing, @vid, @bold.\n\n@-봇에 대한 자세한 정보\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index b3b45ca85..b0b9bd761 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -90,6 +90,7 @@ Als je reacties inschakelt kunnen deelnemers reageren op je bericht in het kanaal. Contacten aan je kanaal toevoegen Deze link kan gedeeld worden met anderen en je kanaal kan worden gevonden via de zoekfunctie. + link Deelnemen aan je kanaal kan door deze link te volgen, je kunt de link altijd intrekken. Beschrijving @@ -117,6 +118,8 @@ Een kanaalnaam moet minimaal 5 tekens hebben. De naam mag niet langer zijn dan 32 tekens. Sorry, begincijfers zijn niet toegestaan. + + Naam controleren... %1$s is beschikbaar. Deelnemers @@ -128,6 +131,7 @@ Kanaal echt verlaten? Je raakt alle berichten in dit kanaal kwijt. Wijzig + Als je een publieke link voor je kanaal instelt kan iedereen deze vinden en deelnemen via de zoekfunctie.\n\nStel geen link in als je je kanaal privé wilt houden. Stel een link in voor je publieke kanaal, om deze vindbaar te maken via de zoekfunctie en te delen met anderen.\n\nWil je dit niet dan kun je een privé-kanaal aanmaken. Kanaal gemaakt @@ -169,7 +173,7 @@ %1$s heeft een locatie gestuurd naar het kanaal %2$s %1$s heeft een bestand gestuurd naar het kanaal %2$s %1$s heeft een GIF gestuurd naar het kanaal %2$s - %1$s heeft een geluidsbestand gestuurd naar het kanaal %2$s + %1$s heeft een spraakbericht gestuurd naar het kanaal %2$s %1$s heeft een sticker gestuurd naar het kanaal %2$s %1$s plaatste een bericht %1$s plaatste een foto @@ -180,6 +184,13 @@ %1$s plaatste een GIF %1$s plaatste een spraakbericht %1$s plaatste een sticker + Wie kan deelnemers toevoegen? + Alle deelnemers + Alleen beheerders + Berichtgeving voor deelnemers + Geen berichtgeving voor deelnemers + Ondertekenen + Beheerdersnaam bij alle uitgaande berichten. Nieuwe verzendlijst Naam van lijst @@ -211,11 +222,11 @@ aan het typen is aan het typen zijn aan het typen - %1$s neemt geluid op + %1$s neemt een spraakbericht op... %1$s verstuurt een foto %1$s verstuurt een video %1$s verstuurt een bestand - geluid opnemen + neemt een spraakbericht op... foto versturen video versturen bestand versturen @@ -284,7 +295,7 @@ %1$s heeft je een locatie gestuurd %1$s heeft je een bestand gestuurd %1$s heeft je een GIF gestuurd - %1$s heeft je een geluidsbestand gestuurd + %1$s heeft je een spraakbericht gestuurd %1$s heeft je een sticker gestuurd %1$s @ %2$s: %3$s %1$s heeft een bericht gestuurd naar de groep %2$s @@ -294,7 +305,7 @@ %1$s heeft een locatie gestuurd naar de groep %2$s %1$s heeft een bestand gestuurd naar de groep %2$s %1$s heeft een GIF gestuurd naar de groep %2$s - %1$s heeft een geluidsbestand gestuurd naar de groep %2$s + %1$s heeft een spraakbericht gestuurd naar de groep %2$s %1$s heeft een sticker gestuurd naar de groep %2$s %1$s heeft je uitgenodigd voor de groep %2$s %1$s heeft de naam van de groep %2$s gewijzigd @@ -331,6 +342,7 @@ Nieuw bericht Bericht versturen naar + Nadat je de groep hebt aangemaakt kun je meer gebruikers toevoegen en omzetten naar een supergroep. Groepsnaam Groepsnaam %1$d/%2$d deelnemers @@ -380,7 +392,8 @@ Encryptiesleutel Zelfvernietigingstimer Uit - Dit is een weergave van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
]]>Als deze afbeelding er bij ]]>%2$s]]> hetzelfde uitziet, is jullie chat 200%% beveiligd.
]]>Lees meer op telegram.org.
+ Deze afbeelding en tekst zijn afgeleid van de encryptiesleutel voor deze geheime chat met ]]>%1$s]]>.
]]>Als dit er hetzelfde uitziet op het apparaat van ]]>%2$s]]>, dan is end-to-end-encryptie gegarandeerd.
]]>Lees meer op telegram.org
+ https://telegram.org/faq#secret-chats Onbekend Info Telefoon @@ -411,6 +424,7 @@ Link kopiëren Verwijder Nog geen stickers + Je hebt het maximale aantal stickerbundels bereikt. Meldingen gereset Tekstgrootte berichten @@ -477,6 +491,7 @@ Bij roaming Geen media GIF\'s automatisch afspelen + Houd bij oor Opslaan in galerij Naam wijzigen Prioriteit @@ -507,6 +522,8 @@ keer binnen minuten + Linkvoorvertoningen + Geheime chats Cache-instellingen Lokale database @@ -606,6 +623,15 @@ Schaduwen Korrel Scherper + Vervagen + Tint + SCHADUWEN + ACCENTUEREN + Curven + ALLE + ROOD + GROEN + BLAUW Vager Uit Lineair @@ -620,6 +646,7 @@ Onderschrift toevoegen Foto-onderschrift Video-onderschrift + Onderschrift Twee-staps-verificatie Extra wachtwoord instellen @@ -702,6 +729,18 @@ Sorry, te veel verzoeken. Momenteel is het niet mogelijk om de privacyinstellingen te wijzigen, even geduld alsjeblieft. Logt alle apparaten behalve deze uit. Gebruiker vasthouden om te verwijderen. + Groepen + Wie kan me toevoegen aan groepchats? + Je kunt met precisie bepalen wie je aan groepen en kanalen mag toevoegen. + Altijd toestaan + Nooit toestaan + Altijd toestaan... + Nooit toestaan... + Deze gebruikers altijd toestaan of verbieden je aan groepen en kanalen toe te voegen. + Wijzig wie je aan groepen en kanalen kan toevoegen. + Je kunt deze gebruiker niet toevoegen aan groepen vanwege de privacyinstellingen van deze gebruiker. + Je kunt deze gebruiker niet toevoegen aan kanalen vanwege de privacyinstellingen van deze gebruiker. + Je kan geen groep maken met deze gebruikers vanwege de privacyinstellingen van deze gebruikers. Video bewerken Originele video @@ -773,7 +812,7 @@ Contact Bestand Sticker - Geluidsbestand + Spraakbericht Jij Schermafdruk gemaakt! un1 heeft een schermafdruk gemaakt! @@ -818,6 +857,10 @@ Sorry, deze functie is momenteel niet beschikbaar in jouw land. Er is geen Telegram-account met deze gebruikersnaam. Deze bot kan geen groepslid worden. + Wil je uitgebreide link-voorvertoning inschakelen voor geheime chats? Let op: deze worden gegenereerd op onze servers. + Let op: inline-bots worden aangeboden door externe ontwikkelaars. Voor de werking van de bot worden de karakters die je na de botnaam typt naar deze ontwikkelaar verstuurd. + Wil je \"Houd bij oor\" inschakelen voor spraakberichten? + Je mag dit bericht niet bewerken. Telegram heeft toegang tot je contacten nodig zodat je kan chatten met je vrienden vanaf al je apparaten. Telegram heeft toegang tot je opslaggeheugen nodig zodat je foto\'s, video\'s, muziek en andere media kunt opslaan en versturen. @@ -998,12 +1041,18 @@ Bijlage: %1$d video\'s Bijlage: %1$d video\'s Bijlage: %1$d video\'s - Bijlage: %1$d geluidsbestanden - Bijlage: 1 geluidsbestand - Bijlage: %1$d geluidsbestanden - Bijlage: %1$d geluidsbestanden - Bijlage: %1$d geluidsbestanden - Bijlage: %1$d geluidsbestanden + Bijlage: %1$d muziekbestanden + Doorgestuurd muziekbestand + Bijlage: %1$d muziekbestanden + Bijlage: %1$d muziekbestanden + Bijlage: %1$d muziekbestanden + Bijlage: %1$d muziekbestanden + Bijlage: %1$d spraakberichten + Bijlage: 1 spraakbericht + Bijlage: %1$d spraakberichten + Bijlage: %1$d spraakberichten + Bijlage: %1$d spraakberichten + Bijlage: %1$d spraakberichten Bijlage: %1$d locaties Bijlage: 1 locatie Bijlage: %1$d locaties @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s om %2$s - - Telegram voor Android is bijgewerkt. Nieuw in versie 3.4.0:\n\nGIF-revolutie: 20 keer zo snel GIF\'s sturen en downloaden. Speel ze automatisch af en sla je favorieten op in het stickerpaneel.\n\nmeer over GIFs:\nhttps://telegram.org/blog/gif-revolution\n\nInline-bots: Voeg botcontent toe aan chats op een nieuwe manier! Geef in het invoerveld de naam van een bot en je commando in en stuur de resultaten naar je chatpartner. Probeer het eens met “@gif dog”. Voorbeelden: @gif, @wiki, @bing, @vid, @bold.\n\nMeer over inline-bots:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index a68d28d94..77a6fee48 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -90,6 +90,7 @@ Se você habilitar comentários, pessoas poderão discutir seu post no canal. Adicionar contatos no canal Pessoas podem compartilhar esse link com outros e encontrar seu canal usando a busca do Telegram. + link Pessoas podem entrar em seu canal com este link. Você pode desativar o link quando quiser. Descrição @@ -117,6 +118,8 @@ Nome do canal deve ter pelo menos 5 caracteres. O nome não pode exceder 32 caracteres. Nome do canal não pode iniciar com número. + + Verificando nome... %1$s está disponível. Membros @@ -128,6 +131,7 @@ Você tem certeza que deseja sair do canal? Você perderá todas as mensagens desse canal. Editar + Por favor, note que ao escolher um link público para o seu canal, qualquer um poderá encontrá-lo na busca e entrar.\n\nNão crie um link se você deseja que seu canal seja privado. Por favor, escolha um link para o seu canal público, assim as pessoas poderão encontrá-lo na busca e compartilhar com outros.\n\nSe não estiver interessado, sugerimos que crie um canal privado. Canal criado @@ -169,7 +173,7 @@ %1$s enviou uma localização ao canal %2$s %1$s enviou um arquivo ao canal %2$s %1$s enviou um GIF ao canal %2$s - %1$s enviou um áudio ao canal %2$s + %1$s enviou uma mensagem ao canal %2$s %1$s enviou um sticker ao canal %2$s %1$s postou uma mensagem %1$s postou uma foto @@ -180,6 +184,13 @@ %1$s postou um GIF %1$s postou uma mensagem de voz %1$s postou um sticker + Quem pode adicionar novos membros? + Todos os Membros + Somente Administradores + Os membros serão notificados quando você postar + Os membros não serão notificados quando você postar + Assinar Mensagens + Adicionar nomes dos administradores nas mensagens postadas. Nova Lista de Transmissão Digite o nome da lista @@ -211,11 +222,11 @@ escrevendo... está escrevendo... estão escrevendo... - %1$s está gravando um áudio... + %1$s está gravando uma mensagem de voz... %1$s está enviando uma foto... %1$s está enviando um vídeo... %1$s está enviando um arquivo... - gravando áudio... + gravando mensagem de voz... enviando foto... enviando vídeo... enviando arquivo... @@ -284,7 +295,7 @@ %1$s enviou uma localização %1$s lhe enviou um arquivo %1$s te enviou um GIF - %1$s te enviou um áudio + %1$s enviou uma mensagem de voz %1$s lhe enviou um sticker %1$s @ %2$s: %3$s %1$s enviou uma mensagem para o grupo %2$s @@ -294,7 +305,7 @@ %1$s enviou uma localização para o grupo %2$s %1$s enviou um arquivo para o grupo %2$s %1$s enviou um GIF para o grupo %2$s - %1$s enviou um áudio para o grupo %2$s + %1$s enviou uma mensagem para o grupo %2$s %1$s enviou um sticker ao grupo %2$s %1$s convidou você para o grupo %2$s %1$s editou o nome do grupo %2$s @@ -331,6 +342,7 @@ Nova Mensagem Enviar mensagem para... + Você poderá adicionar mais usuários após finalizar a criação do grupo e convertê-lo em um supergrupo. Digite o nome do grupo Nome do grupo %1$d/%2$d membros @@ -349,7 +361,7 @@ Qualquer um com Telegram instalado poderá entrar no seu grupo abrindo este link. Administradores de Conversas - Todos os membros são Administradores + Todos São Administradores Todos os membros podem adicionar novos membros, editar o nome e a foto do grupo. Somente administradores podem adicionar e remover membros, editar nome foto do grupo. @@ -380,7 +392,8 @@ Chave criptográfica Tempo de autodestruição Desativado - Esta imagem é uma visualização da chave criptográfica para este chat secreto com ]]>%1$s]]>.
]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
]]>Saiba mais em telegram.org
+ Essa imagem e texto foram derivadas da chave criptográfica para este chat secreto com ]]>%1$s]]>.
]]>Se você vê o mesmo no dispositivo de ]]>%2$s\'s]]>, a criptografia ponta a ponta está garantida.
]]>Leia mais em telegram.org
+ https://telegram.org/faq/br#chats-secretos Desconhecido Info Telefone @@ -411,6 +424,7 @@ Copiar link Remover Nenhum sticker + Desculpe, você alcançou o limite máximo de pacotes de sticker. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -477,6 +491,7 @@ Quando em roaming Sem mídia Auto-Reproduzir GIFs + Levantar para Falar Salvar na galeria Editar nome Prioridade @@ -507,6 +522,8 @@ vezes a cada minutos + Pré-visualização de Link + Chats secretos Configurações de Cache Banco de Dados Local @@ -606,6 +623,15 @@ Sombras Granulado Nitidez + Fade + Matiz + SOMBRAS + LUZES + Curvas + TUDO + VERMELHO + VERDE + AZUL Desfoque Desativado Linear @@ -620,6 +646,7 @@ Adicionar legenda... Legenda da Foto Legenda do Vídeo + Legenda Verificação em duas etapas Configurar senha adicional @@ -702,6 +729,18 @@ Desculpe, muitas solicitações. Impossível alterar os ajustes de privacidade agora, por favor aguarde. Sair de todos os dispositivos, exceto este. Toque e segure no usuário para remover. + Grupos + Quem pode me adicionar em grupos? + Você pode restringir quem pode te adicionar em grupos ou canais com precisão. + Sempre Permitir + Nunca Permitir + Sempre permitir... + Nunca permitir... + Esses usuários poderão ou não te adicionar em grupos e canais, dependendo de suas configurações. + Alterar quem pode te adicionar em grupos ou canais. + Desculpe, você não pode adicionar esse usuário a grupos devido às configurações de privacidade dele. + Desculpe, você não pode adicionar esse usuário a canais devido às configurações de privacidade dele. + Você não pode criar um grupo com esses usuários devido as configurações de privacidade deles. Editar Vídeo Vídeo Original @@ -748,14 +787,14 @@ Você entrou para o grupo via link de convite un1 entrou para o grupo via link de convite un1 removeu un2 - un1 saiu do grupo + un1 deixou o grupo un1 adicionou un2 un1 removeu foto do grupo un1 alterou a foto do grupo un1 alterou o nome do grupo para un2 un1 criou o grupo Você removeu un2 - Você saiu do grupo + Você deixou o grupo Você adicionou un2 Você removeu a foto do grupo Você alterou a foto do grupo @@ -765,7 +804,7 @@ un1 adicionou você un1 retornou ao grupo Você retornou ao grupo - Esta mensagem não é suportada na sua versão do Telegram. Para visualiza-la atualize seu aplicativo em https://telegram.org/update + Esta mensagem não é suportada na sua versão do Telegram. Para visualizá-la atualize seu aplicativo em https://telegram.org/update Foto Vídeo GIF @@ -773,7 +812,7 @@ Contato Arquivo Sticker - Áudio + Mensagem de voz Você Você realizou uma captura da tela! un1 realizou uma captura da tela! @@ -818,6 +857,10 @@ Desculpe, esta funcionalidade não está disponível para seu país. Não há conta do Telegram com esse nome de usuário Esse bot não pode entrar em grupos. + Você gostaria de ativar a pré-visualização estendida de links em Chats Secretos? Note que a pré-visualização é gerada nos servidores do Telegram. + Os bots integrados são fornecidos por desenvolvedores terceiros. Para o bot funcionar, os símbolos que você digita depois do nome de usuário do bot são enviados para o respectivo desenvolvedor. + Gostaria de habilitar o \"Levantar para Falar\" para mensagens de voz? + Desculpe, você não pode editar essa mensagem. Telegram precisa acessar seus contatos para que você possa se conectar aos seus amigos em todos os seus dispositivos. Telegram precisa acessar seu armazenamento para que você possa enviar e salvar fotos, vídeos, músicas e outras mídias. @@ -854,7 +897,7 @@ %1$d membros %1$d membros e mais %1$d pessoas estão escrevendo - e mais %1$d pessoa está escrevendo + e mais %1$d estão digitando e mais %1$d pessoas estão escrevendo e mais %1$d pessoas estão escrevendo e mais %1$d pessoas estão escrevendo @@ -998,12 +1041,18 @@ %1$d vídeos encaminhados %1$d vídeos encaminhados %1$d vídeos encaminhados - %1$d áudios encaminhados - Áudio encaminhado - %1$d áudios encaminhados - %1$d áudios encaminhados - %1$d áudios encaminhados - %1$d áudios encaminhados + %1$d músicas encaminhadas + Música encaminhada + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d mensagens de voz encaminhadas + Mensagem de voz encaminhada + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas %1$d localizações encaminhadas Localização encaminhada %1$d localizações encaminhadas @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s às %2$s - - O Telegram para Android foi atualizado. Novidades da versão 3.4.0:\n\nRevolução do GIF: baixe e envie 20x mais rápido, reprodução automática, salve seus GIFs favoritos numa aba dedicada no painel de stickers.\n\nMais sobre GIFs:\nhttps://telegram.org/blog/gif-revolution\n\nBots integrados: Novo modo de inserir conteúdo de bots numa conversa. Digite o nome de usuário do bot e um comando na mensagem e envie o resultado na conversa. Tente usar "@gif gato" na conversa. Ex. de bots: @gif, @wiki, @bing, @vid, @bold.\n\nMais sobre bots integrados:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index b4ea9c87c..afd42f469 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -90,6 +90,7 @@ Se você habilitar comentários, pessoas poderão discutir seu post no canal. Adicionar contatos no canal Pessoas podem compartilhar esse link com outros e encontrar seu canal usando a busca do Telegram. + link Pessoas podem entrar em seu canal com este link. Você pode desativar o link quando quiser. Descrição @@ -117,6 +118,8 @@ Nome do canal deve ter pelo menos 5 caracteres. O nome não pode exceder 32 caracteres. Nome do canal não pode iniciar com número. + + Verificando nome... %1$s está disponível. Membros @@ -128,6 +131,7 @@ Você tem certeza que deseja sair do canal? Você perderá todas as mensagens desse canal. Editar + Por favor, note que ao escolher um link público para o seu canal, qualquer um poderá encontrá-lo na busca e entrar.\n\nNão crie um link se você deseja que seu canal seja privado. Por favor, escolha um link para o seu canal público, assim as pessoas poderão encontrá-lo na busca e compartilhar com outros.\n\nSe não estiver interessado, sugerimos que crie um canal privado. Canal criado @@ -169,7 +173,7 @@ %1$s enviou uma localização ao canal %2$s %1$s enviou um arquivo ao canal %2$s %1$s enviou um GIF ao canal %2$s - %1$s enviou um áudio ao canal %2$s + %1$s enviou uma mensagem ao canal %2$s %1$s enviou um sticker ao canal %2$s %1$s postou uma mensagem %1$s postou uma foto @@ -180,6 +184,13 @@ %1$s postou um GIF %1$s postou uma mensagem de voz %1$s postou um sticker + Quem pode adicionar novos membros? + Todos os Membros + Somente Administradores + Os membros serão notificados quando você postar + Os membros não serão notificados quando você postar + Assinar Mensagens + Adicionar nomes dos administradores nas mensagens postadas. Nova Lista de Transmissão Digite o nome da lista @@ -211,11 +222,11 @@ escrevendo... está escrevendo... estão escrevendo... - %1$s está gravando um áudio... + %1$s está gravando uma mensagem de voz... %1$s está enviando uma foto... %1$s está enviando um vídeo... %1$s está enviando um arquivo... - gravando áudio... + gravando mensagem de voz... enviando foto... enviando vídeo... enviando arquivo... @@ -284,7 +295,7 @@ %1$s enviou uma localização %1$s lhe enviou um arquivo %1$s te enviou um GIF - %1$s te enviou um áudio + %1$s enviou uma mensagem de voz %1$s lhe enviou um sticker %1$s @ %2$s: %3$s %1$s enviou uma mensagem para o grupo %2$s @@ -294,7 +305,7 @@ %1$s enviou uma localização para o grupo %2$s %1$s enviou um arquivo para o grupo %2$s %1$s enviou um GIF para o grupo %2$s - %1$s enviou um áudio para o grupo %2$s + %1$s enviou uma mensagem para o grupo %2$s %1$s enviou um sticker ao grupo %2$s %1$s convidou você para o grupo %2$s %1$s editou o nome do grupo %2$s @@ -331,6 +342,7 @@ Nova Mensagem Enviar mensagem para... + Você poderá adicionar mais usuários após finalizar a criação do grupo e convertê-lo em um supergrupo. Digite o nome do grupo Nome do grupo %1$d/%2$d membros @@ -349,7 +361,7 @@ Qualquer um com Telegram instalado poderá entrar no seu grupo abrindo este link. Administradores de Conversas - Todos os membros são Administradores + Todos São Administradores Todos os membros podem adicionar novos membros, editar o nome e a foto do grupo. Somente administradores podem adicionar e remover membros, editar nome foto do grupo. @@ -380,7 +392,8 @@ Chave criptográfica Tempo de autodestruição Desativado - Esta imagem é uma visualização da chave criptográfica para este chat secreto com ]]>%1$s]]>.
]]>Se esta imagem aparecer da mesma forma no telefone de ]]>%2$s\'s]]>, sua conversa é 200%% segura.
]]>Saiba mais em telegram.org
+ Essa imagem e texto foram derivadas da chave criptográfica para este chat secreto com ]]>%1$s]]>.
]]>Se você vê o mesmo no dispositivo de ]]>%2$s\'s]]>, a criptografia ponta a ponta está garantida.
]]>Leia mais em telegram.org
+ https://telegram.org/faq/br#chats-secretos Desconhecido Info Telefone @@ -411,6 +424,7 @@ Copiar link Remover Nenhum sticker + Desculpe, você alcançou o limite máximo de pacotes de sticker. Restaurar todas as configurações de notificação Tamanho do texto nas mensagens @@ -477,6 +491,7 @@ Quando em roaming Sem mídia Auto-Reproduzir GIFs + Levantar para Falar Salvar na galeria Editar nome Prioridade @@ -507,6 +522,8 @@ vezes a cada minutos + Pré-visualização de Link + Chats secretos Configurações de Cache Banco de Dados Local @@ -606,6 +623,15 @@ Sombras Granulado Nitidez + Fade + Matiz + SOMBRAS + LUZES + Curvas + TUDO + VERMELHO + VERDE + AZUL Desfoque Desativado Linear @@ -620,6 +646,7 @@ Adicionar legenda... Legenda da Foto Legenda do Vídeo + Legenda Verificação em duas etapas Configurar senha adicional @@ -702,6 +729,18 @@ Desculpe, muitas solicitações. Impossível alterar os ajustes de privacidade agora, por favor aguarde. Sair de todos os dispositivos, exceto este. Toque e segure no usuário para remover. + Grupos + Quem pode me adicionar em grupos? + Você pode restringir quem pode te adicionar em grupos ou canais com precisão. + Sempre Permitir + Nunca Permitir + Sempre permitir... + Nunca permitir... + Esses usuários poderão ou não te adicionar em grupos e canais, dependendo de suas configurações. + Alterar quem pode te adicionar em grupos ou canais. + Desculpe, você não pode adicionar esse usuário a grupos devido às configurações de privacidade dele. + Desculpe, você não pode adicionar esse usuário a canais devido às configurações de privacidade dele. + Você não pode criar um grupo com esses usuários devido as configurações de privacidade deles. Editar Vídeo Vídeo Original @@ -748,14 +787,14 @@ Você entrou para o grupo via link de convite un1 entrou para o grupo via link de convite un1 removeu un2 - un1 saiu do grupo + un1 deixou o grupo un1 adicionou un2 un1 removeu foto do grupo un1 alterou a foto do grupo un1 alterou o nome do grupo para un2 un1 criou o grupo Você removeu un2 - Você saiu do grupo + Você deixou o grupo Você adicionou un2 Você removeu a foto do grupo Você alterou a foto do grupo @@ -765,7 +804,7 @@ un1 adicionou você un1 retornou ao grupo Você retornou ao grupo - Esta mensagem não é suportada na sua versão do Telegram. Para visualiza-la atualize seu aplicativo em https://telegram.org/update + Esta mensagem não é suportada na sua versão do Telegram. Para visualizá-la atualize seu aplicativo em https://telegram.org/update Foto Vídeo GIF @@ -773,7 +812,7 @@ Contato Arquivo Sticker - Áudio + Mensagem de voz Você Você realizou uma captura da tela! un1 realizou uma captura da tela! @@ -818,6 +857,10 @@ Desculpe, esta funcionalidade não está disponível para seu país. Não há conta do Telegram com esse nome de usuário Esse bot não pode entrar em grupos. + Você gostaria de ativar a pré-visualização estendida de links em Chats Secretos? Note que a pré-visualização é gerada nos servidores do Telegram. + Os bots integrados são fornecidos por desenvolvedores terceiros. Para o bot funcionar, os símbolos que você digita depois do nome de usuário do bot são enviados para o respectivo desenvolvedor. + Gostaria de habilitar o \"Levantar para Falar\" para mensagens de voz? + Desculpe, você não pode editar essa mensagem. Telegram precisa acessar seus contatos para que você possa se conectar aos seus amigos em todos os seus dispositivos. Telegram precisa acessar seu armazenamento para que você possa enviar e salvar fotos, vídeos, músicas e outras mídias. @@ -854,7 +897,7 @@ %1$d membros %1$d membros e mais %1$d pessoas estão escrevendo - e mais %1$d pessoa está escrevendo + e mais %1$d estão digitando e mais %1$d pessoas estão escrevendo e mais %1$d pessoas estão escrevendo e mais %1$d pessoas estão escrevendo @@ -998,12 +1041,18 @@ %1$d vídeos encaminhados %1$d vídeos encaminhados %1$d vídeos encaminhados - %1$d áudios encaminhados - Áudio encaminhado - %1$d áudios encaminhados - %1$d áudios encaminhados - %1$d áudios encaminhados - %1$d áudios encaminhados + %1$d músicas encaminhadas + Música encaminhada + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d músicas encaminhadas + %1$d mensagens de voz encaminhadas + Mensagem de voz encaminhada + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas + %1$d mensagens de voz encaminhadas %1$d localizações encaminhadas Localização encaminhada %1$d localizações encaminhadas @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s às %2$s - - O Telegram para Android foi atualizado. Novidades da versão 3.4.0:\n\nRevolução do GIF: baixe e envie 20x mais rápido, reprodução automática, salve seus GIFs favoritos numa aba dedicada no painel de stickers.\n\nMais sobre GIFs:\nhttps://telegram.org/blog/gif-revolution\n\nBots integrados: Novo modo de inserir conteúdo de bots numa conversa. Digite o nome de usuário do bot e um comando na mensagem e envie o resultado na conversa. Tente usar "@gif gato" na conversa. Ex. de bots: @gif, @wiki, @bing, @vid, @bold.\n\nMais sobre bots integrados:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 2a2b4e79c..ae8892580 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -90,6 +90,7 @@ If you enable comments, people will be able to discuss your posts in the channel. Add contacts to your channel People can share this link with others and find your channel using Telegram search. + link People can join your channel by following this link. You can revoke the link any time. Description @@ -117,6 +118,8 @@ Channel names must have at least 5 characters. The name must not exceed 32 characters. Channel names can\'t start with a number. + + Checking name… %1$s is available. Members @@ -128,6 +131,7 @@ Are you sure you want to leave the channel? You will lose all messages in this channel. Edit + Please note that if you choose a public link for your channel, anyone will be able to find it in search and join.\n\nDo not create this link if you want your channel to stay private. Please choose a link for your public channel, so that people can find it in search and share with others.\n\nIf you\'re not interested, we suggest creating a private channel instead. Channel created @@ -169,7 +173,7 @@ %1$s sent a location to the channel %2$s %1$s sent a file to the channel %2$s %1$s sent a GIF to the channel %2$s - %1$s sent an audio to the channel %2$s + %1$s sent a voice message to the channel %2$s %1$s sent a sticker to the channel %2$s %1$s posted a message %1$s posted a photo @@ -180,6 +184,13 @@ %1$s posted a GIF %1$s posted a voice message %1$s posted a sticker + Who can add new members? + All Members + Only Admins + Members will be notified when you post + Members will not be notified when you post + Sign Messages + Add names of the admins to the messages they post. New Broadcast List Enter list name @@ -211,11 +222,11 @@ typing... is typing... are typing... - %1$s is recording audio... + %1$s is recording voice message... %1$s is sending photo... %1$s is sending video... %1$s is sending file... - recording audio... + recording voice message... sending photo... sending video... sending file... @@ -284,7 +295,7 @@ %1$s sent you a location %1$s sent you a file %1$s sent you a GIF - %1$s sent you an audio + %1$s sent you a voice message %1$s sent you a sticker %1$s @ %2$s: %3$s %1$s sent a message to the group %2$s @@ -294,7 +305,7 @@ %1$s sent a location to the group %2$s %1$s sent a file to the group %2$s %1$s sent a GIF to the group %2$s - %1$s sent an audio to the group %2$s + %1$s sent a voice message to the group %2$s %1$s sent a sticker to the group %2$s %1$s invited you to the group %2$s %1$s edited the group\'s %2$s name @@ -331,6 +342,7 @@ New Message Send message to... + You will be able to add more users after you finish creating the group and convert it to a supergroup. Enter group name Group name %1$d/%2$d members @@ -380,7 +392,8 @@ Encryption Key Self-Destruct Timer Off - This image is a visualization of the encryption key for this secret chat with ]]>%1$s]]>.
]]>If this image looks the same on ]]>%2$s\'s]]> phone, your chat is 200%% secure.
]]>Learn more at telegram.org
+ This image and text were derived from the encryption key for this secret chat with ]]>%1$s]]>.
]]>If they look the same on ]]>%2$s\'s]]> device, end-to-end encryption is guaranteed.
]]>Learn more at telegram.org
+ https://telegram.org/faq#secret-chats Unknown Info Phone @@ -411,6 +424,7 @@ Copy link Remove No stickers yet + Sorry, you have reached the maximum number of sticker sets. Reset all notification settings to default Messages Text Size @@ -477,6 +491,7 @@ When roaming No media Autoplay GIFs + Raise to Speak Save to gallery Edit name Priority @@ -507,6 +522,8 @@ times within minutes + Link Previews + Secret chats Cache Settings Local Database @@ -606,6 +623,15 @@ Shadows Grain Sharpen + Fade + Tint + SHADOWS + HIGHLIGHTS + Curves + ALL + RED + GREEN + BLUE Blur Off Linear @@ -620,6 +646,7 @@ Add a caption... Photo Caption Video Caption + Caption Two-Step Verification Set Additional Password @@ -702,6 +729,18 @@ Sorry, too many requests. Unable to change privacy settings now, please wait. Logs out all devices except for this one. Tap and hold on user to delete. + Groups + Who can add me to group chats? + You can restrict who can add you to groups and channels with granular precision. + Always Allow + Never Allow + Always allow... + Never allow... + These users will or will not be able to add you to groups and channels regardless of the settings above. + Change who can add you to groups and channels. + Sorry, you can\'t add this user to groups because of user\'s privacy settings. + Sorry, you can\'t add this user to channels because of user\'s privacy settings. + Sorry, you can\'t create a group with these users because of their privacy settings. Edit Video Original Video @@ -773,7 +812,7 @@ Contact File Sticker - Audio + Voice message You You took a screenshot! un1 took a screenshot! @@ -818,6 +857,10 @@ Sorry, this feature is currently not available in your country. There is no Telegram account with this username. This bot can\'t join groups. + Would you like to enable extended link previews in Secret Chats? Note that link previews are generated on Telegram servers. + Please note that inline bots are provided by third-party developers. For the bot to work, the symbols you type after the bot\'s username are sent to the respective developer. + Would you like to enable "Raise to speak" for voice messages? + Sorry, you can\'t edit this message. Telegram needs access to your contacts so that you can connect with your friends across all your devices. Telegram needs access to your storage so that you can send and save photos, videos, music and other media. @@ -998,12 +1041,18 @@ %1$d forwarded videos %1$d forwarded videos %1$d forwarded videos - %1$d forwarded audios - Forwarded audio - %1$d forwarded audios - %1$d forwarded audios - %1$d forwarded audios - %1$d forwarded audios + %1$d forwarded tracks + Forwarded track + %1$d forwarded tracks + %1$d forwarded tracks + %1$d forwarded tracks + %1$d forwarded tracks + %1$d forwarded voice messages + Forwarded voice message + %1$d forwarded voice messages + %1$d forwarded voice messages + %1$d forwarded voice messages + %1$d forwarded voice messages %1$d forwarded locations Forwarded location %1$d forwarded locations @@ -1039,7 +1088,4 @@ HH:mm h:mm a %1$s at %2$s - - Telegram for Android has been updated. New in version 3.4.0:\n\nGIF revolution: up to 20x faster downloading/sending, autoplay, save GIFs to a dedicated tab on the sticker panel.\n\nMore about GIFs:\nhttps://telegram.org/blog/gif-revolution\n\nInline bots: A new way to add bot content to any chat. Type a bot\'s username and your query in the text field to get instant results and send them to your chat partner. Try typing “@gif dog” in your next chat. Sample bots: @gif, @wiki, @bing, @vid, @bold.\n\nMore about inline bots:\nhttps://telegram.org/blog/inline-bots - 704 \ No newline at end of file diff --git a/build.gradle b/build.gradle index bd99b8d76..26aaecfb0 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,6 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:1.5.0' } } \ No newline at end of file