diff --git a/Dockerfile b/Dockerfile index 17b5ea46e..b9886fbd8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM gradle:6.1.1-jdk8 +FROM gradle:6.5.0-jdk8 ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip ENV ANDROID_API_LEVEL android-30 diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 9f8bdbb59..4604af161 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -5,8 +5,8 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' -def verName = "7.1.3" -def verCode = 88 +def verName = "7.2.0-preview01" +def verCode = 90 def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json") @@ -98,7 +98,7 @@ dependencies { implementation "com.squareup.okhttp3:okhttp:$okHttpVersion" implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okHttpVersion" - implementation 'dnsjava:dnsjava:3.3.0' + implementation 'dnsjava:dnsjava:3.3.1' implementation 'org.dizitart:nitrite:3.4.2' implementation 'cn.hutool:hutool-core:5.4.6' diff --git a/TMessagesProj/jni/CMakeLists.txt b/TMessagesProj/jni/CMakeLists.txt index 6def3d832..ef501d42c 100644 --- a/TMessagesProj/jni/CMakeLists.txt +++ b/TMessagesProj/jni/CMakeLists.txt @@ -444,7 +444,7 @@ target_compile_definitions(sqlite PUBLIC #voip include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt) -set(NATIVE_LIB "tmessages.33") +set(NATIVE_LIB "tmessages.34") #tmessages add_library(${NATIVE_LIB} SHARED diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp index 3b3f73806..5f9215579 100644 --- a/TMessagesProj/jni/TgNetWrapper.cpp +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -80,6 +80,10 @@ jint getCurrentTime(JNIEnv *env, jclass c, jint instanceNum) { return ConnectionsManager::getInstance(instanceNum).getCurrentTime(); } +jint getCurrentDatacenterId(JNIEnv *env, jclass c, jint instanceNum) { + return ConnectionsManager::getInstance(instanceNum).getCurrentDatacenterId(); +} + jint isTestBackend(JNIEnv *env, jclass c, jint instanceNum) { return ConnectionsManager::getInstance(instanceNum).isTestBackend() ? 1 : 0; } @@ -461,6 +465,7 @@ static const char *ConnectionsManagerClassPathName = "org/telegram/tgnet/Connect static JNINativeMethod ConnectionsManagerMethods[] = { {"native_getCurrentTimeMillis", "(I)J", (void *) getCurrentTimeMillis}, {"native_getCurrentTime", "(I)I", (void *) getCurrentTime}, + {"native_getCurrentDatacenterId", "(I)I", (void *) getCurrentDatacenterId}, {"native_isTestBackend", "(I)I", (void *) isTestBackend}, {"native_getTimeDifference", "(I)I", (void *) getTimeDifference}, {"native_sendRequest", "(IJLorg/telegram/tgnet/RequestDelegateInternal;Lorg/telegram/tgnet/QuickAckDelegate;Lorg/telegram/tgnet/WriteToSocketDelegate;IIIZI)V", (void *) sendRequest}, diff --git a/TMessagesProj/jni/lottie.cpp b/TMessagesProj/jni/lottie.cpp index cefb2d89a..429b22d37 100644 --- a/TMessagesProj/jni/lottie.cpp +++ b/TMessagesProj/jni/lottie.cpp @@ -299,7 +299,7 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_createCache(JNIEn for (size_t a = 0; a < info->frameCount; a += framesPerUpdate) { Surface &surfaceToRender = num % 2 == 0 ? surface1 : surface2; num++; - info->animation->renderSync(a, surfaceToRender); + info->animation->renderSync(a, surfaceToRender, true); if (a != 0) { std::unique_lock lk(cacheDoneMutex); cacheDoneCv.wait(lk, [] { return !frameReady.load(); }); @@ -317,6 +317,7 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_createCache(JNIEn //DEBUG_D("sticker time = %d", (int) (ConnectionsManager::getInstance(0).getCurrentTimeMonotonicMillis() - time)); delete[] info->compressBuffer; + delete[] firstBuffer; delete[] secondBuffer; fseek(info->precacheFile, 0, SEEK_SET); uint8_t byte = 1; @@ -332,7 +333,7 @@ JNIEXPORT void Java_org_telegram_ui_Components_RLottieDrawable_createCache(JNIEn } } -JNIEXPORT jint Java_org_telegram_ui_Components_RLottieDrawable_getFrame(JNIEnv *env, jclass clazz, jlong ptr, jint frame, jobject bitmap, jint w, jint h, jint stride) { +JNIEXPORT jint Java_org_telegram_ui_Components_RLottieDrawable_getFrame(JNIEnv *env, jclass clazz, jlong ptr, jint frame, jobject bitmap, jint w, jint h, jint stride, jboolean clear) { if (!ptr || bitmap == nullptr) { return 0; } @@ -384,7 +385,7 @@ JNIEXPORT jint Java_org_telegram_ui_Components_RLottieDrawable_getFrame(JNIEnv * if (!loadedFromCache) { if (!info->nextFrameIsCacheFrame || !info->precache) { Surface surface((uint32_t *) pixels, (size_t) w, (size_t) h, (size_t) stride); - info->animation->renderSync((size_t) frame, surface); + info->animation->renderSync((size_t) frame, surface, clear); info->nextFrameIsCacheFrame = true; } } diff --git a/TMessagesProj/jni/rlottie/inc/rlottie.h b/TMessagesProj/jni/rlottie/inc/rlottie.h index ea0d0da60..296546a9c 100755 --- a/TMessagesProj/jni/rlottie/inc/rlottie.h +++ b/TMessagesProj/jni/rlottie/inc/rlottie.h @@ -345,7 +345,7 @@ public: * * @internal */ - void renderSync(size_t frameNo, Surface &surface); + void renderSync(size_t frameNo, Surface &surface, bool clear); /** * @brief Returns root layer of the composition updated with diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp index 429d6c7f7..743002b83 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieanimation.cpp @@ -44,7 +44,7 @@ public: double frameRate() const { return mModel->frameRate(); } size_t totalFrame() const { return mModel->totalFrame(); } size_t frameAtPos(double pos) const { return mModel->frameAtPos(pos); } - Surface render(size_t frameNo, const Surface &surface); + Surface render(size_t frameNo, const Surface &surface, bool clear); const LOTLayerNode * renderTree(size_t frameNo, const VSize &size); const LayerInfoList &layerInfoList() const @@ -93,7 +93,7 @@ bool AnimationImpl::update(size_t frameNo, const VSize &size) return mCompItem->update(frameNo); } -Surface AnimationImpl::render(size_t frameNo, const Surface &surface) +Surface AnimationImpl::render(size_t frameNo, const Surface &surface, bool clear) { bool renderInProgress = mRenderInProgress.load(); if (renderInProgress) { @@ -104,7 +104,7 @@ Surface AnimationImpl::render(size_t frameNo, const Surface &surface) mRenderInProgress.store(true); update(frameNo, VSize(surface.drawRegionWidth(), surface.drawRegionHeight())); - mCompItem->render(surface); + mCompItem->render(surface, clear); mRenderInProgress.store(false); return surface; @@ -201,9 +201,9 @@ const LOTLayerNode *Animation::renderTree(size_t frameNo, size_t width, return d->renderTree(frameNo, VSize(width, height)); } -void Animation::renderSync(size_t frameNo, Surface &surface) +void Animation::renderSync(size_t frameNo, Surface &surface, bool clear) { - d->render(frameNo, surface); + d->render(frameNo, surface, clear); } const LayerInfoList &Animation::layers() const diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieitem.cpp b/TMessagesProj/jni/rlottie/src/lottie/lottieitem.cpp index 1e86d368a..3221c246d 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieitem.cpp +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieitem.cpp @@ -175,7 +175,7 @@ const LOTLayerNode *LOTCompItem::renderTree() const return mRootLayer->layerNode(); } -bool LOTCompItem::render(const rlottie::Surface &surface) +bool LOTCompItem::render(const rlottie::Surface &surface, bool clear) { VBitmap bitmap(reinterpret_cast(surface.buffer()), surface.width(), surface.height(), surface.bytesPerLine(), @@ -190,7 +190,7 @@ bool LOTCompItem::render(const rlottie::Surface &surface) e->preprocess(clip); } - VPainter painter(&bitmap); + VPainter painter(&bitmap, clear); // set sub surface area for drawing. painter.setDrawRegion( VRect(surface.drawRegionPosX(), surface.drawRegionPosY(), @@ -609,7 +609,7 @@ void LOTCompLayerItem::render(VPainter *painter, const VRle &inheritMask, VPainter srcPainter; VBitmap srcBitmap(size.width(), size.height(), VBitmap::Format::ARGB32); - srcPainter.begin(&srcBitmap); + srcPainter.begin(&srcBitmap, true); renderHelper(&srcPainter, inheritMask, matteRle); srcPainter.end(); painter->drawBitmap(VPoint(), srcBitmap, combinedAlpha() * 255); @@ -669,7 +669,7 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, VPainter srcPainter; src->bitmap().reset(size.width(), size.height(), VBitmap::Format::ARGB32); - srcPainter.begin(&src->bitmap()); + srcPainter.begin(&src->bitmap(), true); src->render(&srcPainter, mask, matteRle); srcPainter.end(); @@ -677,7 +677,7 @@ void LOTCompLayerItem::renderMatteLayer(VPainter *painter, const VRle &mask, VPainter layerPainter; layer->bitmap().reset(size.width(), size.height(), VBitmap::Format::ARGB32); - layerPainter.begin(&layer->bitmap()); + layerPainter.begin(&layer->bitmap(), true); layer->render(&layerPainter, mask, matteRle); // 2.1update composition mode diff --git a/TMessagesProj/jni/rlottie/src/lottie/lottieitem.h b/TMessagesProj/jni/rlottie/src/lottie/lottieitem.h index 80517ac51..2450b4a23 100755 --- a/TMessagesProj/jni/rlottie/src/lottie/lottieitem.h +++ b/TMessagesProj/jni/rlottie/src/lottie/lottieitem.h @@ -70,7 +70,7 @@ public: VSize size() const; void buildRenderTree(); const LOTLayerNode * renderTree()const; - bool render(const rlottie::Surface &surface); + bool render(const rlottie::Surface &surface, bool clear); void setValue(const std::string &keypath, LOTVariant &value); void resetCurrentFrame(); private: diff --git a/TMessagesProj/jni/rlottie/src/vector/vpainter.cpp b/TMessagesProj/jni/rlottie/src/vector/vpainter.cpp index cdcaa11f4..365adcdb3 100755 --- a/TMessagesProj/jni/rlottie/src/vector/vpainter.cpp +++ b/TMessagesProj/jni/rlottie/src/vector/vpainter.cpp @@ -115,17 +115,19 @@ VPainter::VPainter() mImpl = new VPainterImpl; } -VPainter::VPainter(VBitmap *buffer) +VPainter::VPainter(VBitmap *buffer, bool clear) { mImpl = new VPainterImpl; - begin(buffer); + begin(buffer, clear); } -bool VPainter::begin(VBitmap *buffer) +bool VPainter::begin(VBitmap *buffer, bool clear) { mImpl->mBuffer.prepare(buffer); mImpl->mSpanData.init(&mImpl->mBuffer); // TODO find a better api to clear the surface - mImpl->mBuffer.clear(); + if (clear) { + mImpl->mBuffer.clear(); + } return true; } void VPainter::end() {} diff --git a/TMessagesProj/jni/rlottie/src/vector/vpainter.h b/TMessagesProj/jni/rlottie/src/vector/vpainter.h index 2d523370d..2aaf99925 100755 --- a/TMessagesProj/jni/rlottie/src/vector/vpainter.h +++ b/TMessagesProj/jni/rlottie/src/vector/vpainter.h @@ -37,8 +37,8 @@ public: }; ~VPainter(); VPainter(); - VPainter(VBitmap *buffer); - bool begin(VBitmap *buffer); + VPainter(VBitmap *buffer, bool clear); + bool begin(VBitmap *buffer, bool clear); void end(); void setDrawRegion(const VRect ®ion); // sub surface rendering area. void setBrush(const VBrush &brush); diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp index 337343a6c..088ba4374 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -581,6 +581,11 @@ int32_t ConnectionsManager::getCurrentTime() { return (int32_t) (getCurrentTimeMillis() / 1000) + timeDifference; } +uint32_t ConnectionsManager::getCurrentDatacenterId() { + Datacenter *datacenter = getDatacenterWithId(DEFAULT_DATACENTER_ID); + return datacenter != nullptr ? datacenter->getDatacenterId() : INT_MAX; +} + bool ConnectionsManager::isTestBackend() { return testBackend; } @@ -2815,7 +2820,7 @@ std::unique_ptr ConnectionsManager::wrapInLayer(TLObject *object, Data invokeWithLayer *request2 = new invokeWithLayer(); request2->layer = currentLayer; request2->query = std::unique_ptr(request); - if (LOGS_ENABLED) DEBUG_D("wrap in layer %s", typeid(*object).name()); + if (LOGS_ENABLED) DEBUG_D("wrap in layer %s, flags = %d", typeid(*object).name(), request->flags); return std::unique_ptr(request2); } } diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h index c29de5548..7aefaa285 100644 --- a/TMessagesProj/jni/tgnet/ConnectionsManager.h +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -45,6 +45,7 @@ public: int64_t getCurrentTimeMillis(); int64_t getCurrentTimeMonotonicMillis(); int32_t getCurrentTime(); + uint32_t getCurrentDatacenterId(); bool isTestBackend(); int32_t getTimeDifference(); int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate); diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index cc55fe757..0c32babb5 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -502,9 +502,14 @@ android:authorities="${applicationId}.call_sound_provider" android:exported="true" /> - + + + + + + + + top) { animateTo = top - botCell.getTop(); @@ -748,6 +758,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator { if (moveInfoExtended.animateChangeInternal) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1f); + params.animateChange = true; valueAnimator.addUpdateListener(animation -> { params.animateChangeProgress = (float) animation.getAnimatedValue(); chatMessageCell.invalidate(); @@ -950,9 +961,7 @@ public class ChatListItemAnimator extends DefaultItemAnimator { FileLog.d("all animations done"); } - if (!reset) { - recyclerListView.setClipChildren(true); - } + recyclerListView.setClipChildren(true); while (!runOnAnimationsEnd.isEmpty()) { runOnAnimationsEnd.remove(0).run(); } diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChildHelper.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChildHelper.java index 710942bcb..99fc2e3f2 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChildHelper.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/ChildHelper.java @@ -295,9 +295,6 @@ public class ChildHelper { final int offset = getOffset(index); mBucket.remove(offset); mCallback.detachViewFromParent(offset); - if (DEBUG) { - Log.d(TAG, "detach view from parent " + index + ", off:" + offset); - } } /** diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java index 1e8310510..0174ae73c 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/LinearLayoutManager.java @@ -965,12 +965,16 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements return fixOffset; } + public int getStarForFixGap() { + return mOrientationHelper.getStartAfterPadding(); + } + /** * @return The final offset amount for children */ private int fixLayoutStartGap(int startOffset, RecyclerView.Recycler recycler, RecyclerView.State state, boolean canOffsetChildren) { - int gap = startOffset - mOrientationHelper.getStartAfterPadding(); + int gap = startOffset - getStarForFixGap(); int fixOffset = 0; if (gap > 0) { // check if we should fix this gap. @@ -1458,21 +1462,33 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements if (mShouldReverseLayout) { for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); - if (mOrientationHelper.getDecoratedEnd(child) > limit - || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) { - // stop here - recycleChildren(recycler, childCount - 1, i); - return; + if (child != null) { + RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (mOrientationHelper.getDecoratedEnd(child) > limit + || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) { + // stop here + recycleChildren(recycler, childCount - 1, i); + return; + } } } } else { for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (mOrientationHelper.getDecoratedEnd(child) > limit - || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) { - // stop here - recycleChildren(recycler, 0, i); - return; + if (child != null) { + RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (mOrientationHelper.getDecoratedEnd(child) > limit + || mOrientationHelper.getTransformedEndWithDecoration(child) > limit) { + // stop here + recycleChildren(recycler, 0, i); + return; + } } } } @@ -1506,21 +1522,33 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements if (mShouldReverseLayout) { for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (mOrientationHelper.getDecoratedStart(child) < limit - || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) { - // stop here - recycleChildren(recycler, 0, i); - return; + if (child != null) { + RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (mOrientationHelper.getDecoratedStart(child) < limit + || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) { + // stop here + recycleChildren(recycler, 0, i); + return; + } } } } else { for (int i = childCount - 1; i >= 0; i--) { View child = getChildAt(i); - if (mOrientationHelper.getDecoratedStart(child) < limit - || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) { - // stop here - recycleChildren(recycler, childCount - 1, i); - return; + if (child != null) { + RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (mOrientationHelper.getDecoratedStart(child) < limit + || mOrientationHelper.getTransformedStartWithDecoration(child) < limit) { + // stop here + recycleChildren(recycler, childCount - 1, i); + return; + } } } } diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/OrientationHelper.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/OrientationHelper.java index f94e0dd16..0a981802f 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/OrientationHelper.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/OrientationHelper.java @@ -371,7 +371,7 @@ public abstract class OrientationHelper { @Override public int getStartAfterPadding() { - return mLayoutManager.getPaddingTop(); + return mLayoutManager.getStartAfterPadding(); } @Override @@ -418,8 +418,7 @@ public abstract class OrientationHelper { @Override public int getTotalSpace() { - return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop() - - mLayoutManager.getPaddingBottom(); + return mLayoutManager.getTotalSpace(); } @Override diff --git a/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java b/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java index 881135d97..b4106e045 100644 --- a/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java +++ b/TMessagesProj/src/main/java/androidx/recyclerview/widget/RecyclerView.java @@ -902,13 +902,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, // lazy detach occurs, it will receive invalid attach/detach sequencing. child.clearAnimation(); } - if (VERBOSE_TRACING) { - TraceCompat.beginSection("RV removeViewAt"); - } RecyclerView.this.removeViewAt(index); - if (VERBOSE_TRACING) { - TraceCompat.endSection(); - } } @Override @@ -945,9 +939,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, throw new IllegalArgumentException("Called attach on a child which is not" + " detached: " + vh + exceptionLabel()); } - if (DEBUG) { - Log.d(TAG, "reAttach " + vh); - } vh.clearTmpDetachFlag(); } RecyclerView.this.attachViewToParent(child, index, layoutParams); @@ -963,9 +954,6 @@ public class RecyclerView extends ViewGroup implements ScrollingView, throw new IllegalArgumentException("called detach on an already" + " detached child " + vh + exceptionLabel()); } - if (DEBUG) { - Log.d(TAG, "tmpDetach " + vh); - } vh.addFlags(ViewHolder.FLAG_TMP_DETACHED); } } @@ -7564,7 +7552,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, @Override public int getParentStart() { - return LayoutManager.this.getPaddingTop(); + return LayoutManager.this.getParentStart(); } @Override @@ -8841,6 +8829,10 @@ public class RecyclerView extends ViewGroup implements ScrollingView, */ public void removeAndRecycleViewAt(int index, @NonNull Recycler recycler) { final View view = getChildAt(index); + ViewHolder holder = getChildViewHolderInt(view); + if (holder.shouldIgnore()) { + return; + } removeViewAt(index); recycler.recycleView(view); } @@ -10597,6 +10589,22 @@ public class RecyclerView extends ViewGroup implements ScrollingView, /** {@link androidx.recyclerview.R.attr#stackFromEnd} */ public boolean stackFromEnd; } + + /** + * Custom methods for ignoring padding + */ + protected int getParentStart() { + return getPaddingTop(); + } + + + public int getStartAfterPadding() { + return getPaddingTop(); + } + + public int getTotalSpace() { + return getHeight() - getPaddingTop() - getPaddingBottom(); + } } /** @@ -11036,7 +11044,7 @@ public class RecyclerView extends ViewGroup implements ScrollingView, } } - boolean shouldIgnore() { + public boolean shouldIgnore() { return (mFlags & FLAG_IGNORE) != 0; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java index a9dac2f64..cccc4fac0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -92,6 +92,7 @@ import androidx.viewpager.widget.ViewPager; import com.android.internal.telephony.ITelephony; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestTimeDelegate; import org.telegram.tgnet.TLObject; @@ -255,16 +256,22 @@ public class AndroidUtilities { return false; } - public static CharSequence ellipsizeCenterEnd(CharSequence str, String query, int availableWidth, TextPaint textPaint) { + public static CharSequence ellipsizeCenterEnd(CharSequence str, String query, int availableWidth, TextPaint textPaint, int maxSymbols) { try { - StaticLayout staticLayout = new StaticLayout(str, textPaint, Integer.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); int lastIndex = str.length(); + int startHighlightedIndex = str.toString().toLowerCase().indexOf(query); + + if (lastIndex > maxSymbols) { + str = str.subSequence(Math.max(0, startHighlightedIndex - maxSymbols / 2), Math.min(lastIndex, startHighlightedIndex + maxSymbols / 2)); + startHighlightedIndex -= Math.max(0, startHighlightedIndex - maxSymbols / 2); + lastIndex = str.length(); + } + StaticLayout staticLayout = new StaticLayout(str, textPaint, Integer.MAX_VALUE, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); float endOfTextX = staticLayout.getPrimaryHorizontal(lastIndex); if (endOfTextX + textPaint.measureText("...") < availableWidth) { return str; } - int startHighlightedIndex = str.toString().toLowerCase().indexOf(query); int i = startHighlightedIndex + 1; while (i < str.length() - 1 && !Character.isWhitespace(str.charAt(i))) { i++; @@ -372,7 +379,7 @@ public class AndroidUtilities { return url; } - private static void gatherLinks(ArrayList links, Spannable s, Pattern pattern, String[] schemes, Linkify.MatchFilter matchFilter) { + private static void gatherLinks(ArrayList links, Spannable s, Pattern pattern, String[] schemes, Linkify.MatchFilter matchFilter, boolean internalOnly) { Matcher m = pattern.matcher(s); while (m.find()) { int start = m.start(); @@ -381,7 +388,11 @@ public class AndroidUtilities { if (matchFilter == null || matchFilter.acceptMatch(s, start, end)) { LinkSpec spec = new LinkSpec(); - spec.url = makeUrl(m.group(0), schemes, m); + String url = makeUrl(m.group(0), schemes, m); + if (internalOnly && !Browser.isInternalUrl(url, true, null)) { + continue; + } + spec.url = url; spec.start = start; spec.end = end; @@ -410,7 +421,7 @@ public class AndroidUtilities { } } final ArrayList links = new ArrayList<>(); - gatherLinks(links, text, LinkifyPort.PROXY_PATTERN, new String[]{VMESS_PROTOCOL, VMESS1_PROTOCOL, SS_PROTOCOL, SSR_PROTOCOL, TROJAN_PROTOCOL/*, RB_PROTOCOL*/}, sUrlMatchFilter); + gatherLinks(links, text, LinkifyPort.PROXY_PATTERN, new String[]{VMESS_PROTOCOL, VMESS1_PROTOCOL, SS_PROTOCOL, SSR_PROTOCOL, TROJAN_PROTOCOL/*, RB_PROTOCOL*/}, sUrlMatchFilter, false); pruneOverlaps(links); if (links.size() == 0) { return false; @@ -429,6 +440,10 @@ public class AndroidUtilities { } public static boolean addLinks(Spannable text, int mask) { + return addLinks(text, mask, false); + } + + public static boolean addLinks(Spannable text, int mask, boolean internalOnly) { if (text == null || containsUnsupportedCharacters(text.toString()) || mask == 0) { return false; } @@ -437,11 +452,11 @@ public class AndroidUtilities { text.removeSpan(old[i]); } final ArrayList links = new ArrayList<>(); - if ((mask & Linkify.PHONE_NUMBERS) != 0) { + if (!internalOnly && (mask & Linkify.PHONE_NUMBERS) != 0) { Linkify.addLinks(text, Linkify.PHONE_NUMBERS); } if ((mask & Linkify.WEB_URLS) != 0) { - gatherLinks(links, text, LinkifyPort.WEB_URL, new String[]{"http://", "https://", "ton://", "tg://"}, sUrlMatchFilter); + gatherLinks(links, text, LinkifyPort.WEB_URL, new String[]{"http://", "https://", "ton://", "tg://"}, sUrlMatchFilter, internalOnly); } pruneOverlaps(links); if (links.size() == 0) { @@ -677,6 +692,14 @@ public class AndroidUtilities { adjustOwnerClassGuid = classGuid; } + public static void requestAdjustNothing(Activity activity, int classGuid) { + if (activity == null || isTablet()) { + return; + } + activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING); + adjustOwnerClassGuid = classGuid; + } + public static void setAdjustResizeToNothing(Activity activity, int classGuid) { if (activity == null || isTablet()) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java index ff79750d9..67d6b5ef8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -251,7 +251,7 @@ public class ChatObject { public static boolean canAddBotsToChat(TLRPC.Chat chat) { if (isChannel(chat)) { - if (chat != null && chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.creator)) { + if (chat.megagroup && (chat.admin_rights != null && (chat.admin_rights.post_messages || chat.admin_rights.add_admins) || chat.creator)) { return true; } } else { @@ -273,7 +273,7 @@ public class ChatObject { public static boolean isCanWriteToChannel(int chatId, int currentAccount) { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(chatId); - return ChatObject.canSendMessages(chat) || chat != null && chat.megagroup; + return ChatObject.canSendMessages(chat) || chat.megagroup; } public static boolean canWriteToChat(TLRPC.Chat chat) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java index 44b253434..5581ccc11 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadController.java @@ -768,12 +768,12 @@ public class DownloadController extends BaseController implements NotificationCe } if (downloadObject.object instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) downloadObject.object; - getFileLoader().cancelLoadFile(document); + getFileLoader().cancelLoadFile(document, true); } else if (downloadObject.object instanceof TLRPC.Photo) { TLRPC.Photo photo = (TLRPC.Photo) downloadObject.object; TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, AndroidUtilities.getPhotoSize()); if (photoSize != null) { - getFileLoader().cancelLoadFile(photoSize); + getFileLoader().cancelLoadFile(photoSize, true); } } } @@ -783,14 +783,14 @@ public class DownloadController extends BaseController implements NotificationCe if (objects.isEmpty()) { return; } - ArrayList queue = null; + ArrayList queue; if (type == AUTODOWNLOAD_TYPE_PHOTO) { queue = photoDownloadQueue; } else if (type == AUTODOWNLOAD_TYPE_AUDIO) { queue = audioDownloadQueue; } else if (type == AUTODOWNLOAD_TYPE_VIDEO) { queue = videoDownloadQueue; - } else if (type == AUTODOWNLOAD_TYPE_DOCUMENT) { + } else { queue = documentDownloadQueue; } for (int a = 0; a < objects.size(); a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java b/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java index 019ffffc5..bc440d0d8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java @@ -803,6 +803,10 @@ public class EmojiData { return "\uD83C\uDF51".equals(emoji); } + public static boolean isCofinEmoji(String emoji) { + return "⚰️".equals(emoji); + } + static { for (int a = 0; a < emojiToFE0F.length; a++) { emojiToFE0FMap.put(emojiToFE0F[a], true); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/EmuDetector.java b/TMessagesProj/src/main/java/org/telegram/messenger/EmuDetector.java index 9ff49d9b7..adf89aba8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/EmuDetector.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/EmuDetector.java @@ -8,6 +8,8 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Build; import androidx.core.content.ContextCompat; + +import android.os.Environment; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -34,6 +36,10 @@ public class EmuDetector { void onResult(boolean isEmulator); } + private enum EmulatorTypes { + GENY, ANDY, NOX, BLUE, PIPES, X86 + } + private static final String[] PHONE_NUMBERS = { "15555215554", "15555215556", "15555215558", "15555215560", "15555215562", "15555215564", "15555215566", "15555215568", "15555215570", "15555215572", "15555215574", "15555215576", @@ -81,7 +87,14 @@ public class EmuDetector { private static final String[] NOX_FILES = { "fstab.nox", "init.nox.rc", - "ueventd.nox.rc" + "ueventd.nox.rc", + "/BigNoxGameHD", + "/YSLauncher" + }; + + private static final String[] BLUE_FILES = { + "/Android/data/com.bluestacks.home", + "/Android/data/com.bluestacks.settings" }; private static final Property[] PROPERTIES = { @@ -132,6 +145,7 @@ public class EmuDetector { mListPackageName.add("com.google.android.launcher.layouts.genymotion"); mListPackageName.add("com.bluestacks"); mListPackageName.add("com.bignox.app"); + mListPackageName.add("com.vphone.launcher"); } public boolean isCheckTelephony() { @@ -185,23 +199,25 @@ public class EmuDetector { } private boolean checkBasic() { - boolean result = Build.FINGERPRINT.startsWith("generic") - || Build.MODEL.contains("google_sdk") - || Build.MODEL.toLowerCase().contains("droid4x") - || Build.MODEL.contains("Emulator") - || Build.MODEL.contains("Android SDK built for x86") - || Build.MANUFACTURER.contains("Genymotion") - || Build.HARDWARE.equals("goldfish") - || Build.HARDWARE.equals("vbox86") - || Build.PRODUCT.equals("sdk") - || Build.PRODUCT.equals("google_sdk") - || Build.PRODUCT.equals("sdk_x86") - || Build.PRODUCT.equals("vbox86p") - || Build.BOARD.toLowerCase().contains("nox") - || Build.BOOTLOADER.toLowerCase().contains("nox") - || Build.HARDWARE.toLowerCase().contains("nox") - || Build.PRODUCT.toLowerCase().contains("nox") - || Build.SERIAL.toLowerCase().contains("nox"); + boolean result = + Build.BOARD.toLowerCase().contains("nox") + || Build.BOOTLOADER.toLowerCase().contains("nox") + || Build.FINGERPRINT.startsWith("generic") + || Build.MODEL.toLowerCase().contains("google_sdk") + || Build.MODEL.toLowerCase().contains("droid4x") + || Build.MODEL.toLowerCase().contains("emulator") + || Build.MODEL.contains("Android SDK built for x86") + || Build.MANUFACTURER.toLowerCase().contains("genymotion") + || Build.HARDWARE.toLowerCase().contains("goldfish") + || Build.HARDWARE.toLowerCase().contains("vbox86") + || Build.HARDWARE.toLowerCase().contains("android_x86") + || Build.HARDWARE.toLowerCase().contains("nox") + || Build.PRODUCT.equals("sdk") + || Build.PRODUCT.equals("google_sdk") + || Build.PRODUCT.equals("sdk_x86") + || Build.PRODUCT.equals("vbox86p") + || Build.PRODUCT.toLowerCase().contains("nox") + || Build.SERIAL.toLowerCase().contains("nox"); if (result) { return true; @@ -216,13 +232,14 @@ public class EmuDetector { private boolean checkAdvanced() { return checkTelephony() - || checkFiles(GENY_FILES, "Geny") - || checkFiles(ANDY_FILES, "Andy") - || checkFiles(NOX_FILES, "Nox") + || checkFiles(GENY_FILES, EmulatorTypes.GENY) + || checkFiles(ANDY_FILES, EmulatorTypes.ANDY) + || checkFiles(NOX_FILES, EmulatorTypes.NOX) + || checkFiles(BLUE_FILES, EmulatorTypes.BLUE) || checkQEmuDrivers() - || checkFiles(PIPES, "Pipes") + || checkFiles(PIPES, EmulatorTypes.PIPES) || checkIp() - || (checkQEmuProps() && checkFiles(X86_FILES, "X86")); + || (checkQEmuProps() && checkFiles(X86_FILES, EmulatorTypes.X86)); } private boolean checkPackageName() { @@ -313,9 +330,18 @@ public class EmuDetector { return false; } - private boolean checkFiles(String[] targets, String type) { + private boolean checkFiles(String[] targets, EmulatorTypes type) { for (String pipe : targets) { - File qemu_file = new File(pipe); + File qemu_file; + if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + if ((pipe.contains("/") && type == EmulatorTypes.NOX) || type == EmulatorTypes.BLUE) { + qemu_file = new File(Environment.getExternalStorageDirectory() + pipe); + } else { + qemu_file = new File(pipe); + } + } else { + qemu_file = new File(pipe); + } if (qemu_file.exists()) { return true; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 275a40f2b..6a7c01054 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -1018,19 +1018,69 @@ public class FileLoadOperation { } public void cancel() { + cancel(false); + } + + public void cancel(boolean deleteFiles) { Utilities.stageQueue.postRunnable(() -> { - if (state == stateFinished || state == stateFailed) { - return; + if (state != stateFinished && state != stateFailed) { + if (requestInfos != null) { + for (int a = 0; a < requestInfos.size(); a++) { + RequestInfo requestInfo = requestInfos.get(a); + if (requestInfo.requestToken != 0) { + ConnectionsManager.getInstance(currentAccount).cancelRequest(requestInfo.requestToken, true); + } + } + } + onFail(false, 1); } - if (requestInfos != null) { - for (int a = 0; a < requestInfos.size(); a++) { - RequestInfo requestInfo = requestInfos.get(a); - if (requestInfo.requestToken != 0) { - ConnectionsManager.getInstance(currentAccount).cancelRequest(requestInfo.requestToken, true); + if (deleteFiles) { + if (cacheFileFinal != null) { + try { + if (!cacheFileFinal.delete()) { + cacheFileFinal.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + if (cacheFileTemp != null) { + try { + if (!cacheFileTemp.delete()) { + cacheFileTemp.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + if (cacheFileParts != null) { + try { + if (!cacheFileParts.delete()) { + cacheFileParts.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + if (cacheIvTemp != null) { + try { + if (!cacheIvTemp.delete()) { + cacheIvTemp.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + if (cacheFilePreload != null) { + try { + if (!cacheFilePreload.delete()) { + cacheFilePreload.deleteOnExit(); + } + } catch (Exception e) { + FileLog.e(e); } } } - onFail(false, 1); }); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 2d43674f3..eb9a951ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -123,7 +123,7 @@ public class FileLoader extends BaseController { dir = mediaDirs.get(FileLoader.MEDIA_DIR_CACHE); } try { - if (!dir.isDirectory()) { + if (dir != null && !dir.isDirectory()) { dir.mkdirs(); } } catch (Exception e) { @@ -413,10 +413,9 @@ public class FileLoader extends BaseController { int queueType = operation.getQueueType(); LinkedList downloadQueue = getLoadOperationQueue(datacenterId, queueType); SparseIntArray count = getLoadOperationCount(queueType); - if (downloadQueue != null) { - int index = downloadQueue.indexOf(operation); - if (index >= 0) { - downloadQueue.remove(index); + int index = downloadQueue.indexOf(operation); + if (index >= 0) { + downloadQueue.remove(index); if (operation.start()) { count.put(datacenterId, count.get(datacenterId) + 1); } @@ -426,12 +425,11 @@ public class FileLoader extends BaseController { activeFileLoadOperation.add(operation); } } - } else { - pauseCurrentFileLoadOperations(operation); - operation.start(); - if (queueType == QUEUE_TYPE_FILE && !activeFileLoadOperation.contains(operation)) { - activeFileLoadOperation.add(operation); - } + } else { + pauseCurrentFileLoadOperations(operation); + operation.start(); + if (queueType == QUEUE_TYPE_FILE && !activeFileLoadOperation.contains(operation)) { + activeFileLoadOperation.add(operation); } } } @@ -439,27 +437,49 @@ public class FileLoader extends BaseController { } public void cancelLoadFile(TLRPC.Document document) { - cancelLoadFile(document, null, null, null, null); + cancelLoadFile(document, false); + } + + public void cancelLoadFile(TLRPC.Document document, boolean deleteFile) { + cancelLoadFile(document, null, null, null, null, null, deleteFile); } public void cancelLoadFile(SecureDocument document) { - cancelLoadFile(null, document, null, null, null); + cancelLoadFile(null, document, null, null, null, null, false); } public void cancelLoadFile(WebFile document) { - cancelLoadFile(null, null, document, null, null); + cancelLoadFile(null, null, document, null, null, null, false); } public void cancelLoadFile(TLRPC.PhotoSize photo) { - cancelLoadFile(null, null, null, photo.location, null); + cancelLoadFile(photo, false); + } + + public void cancelLoadFile(TLRPC.PhotoSize photo, boolean deleteFile) { + cancelLoadFile(null, null, null, photo.location, null, null, deleteFile); } public void cancelLoadFile(TLRPC.FileLocation location, String ext) { - cancelLoadFile(null, null, null, location, ext); + cancelLoadFile(location, ext, false); } - private void cancelLoadFile(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, final TLRPC.FileLocation location, final String locationExt) { - if (location == null && document == null && webDocument == null && secureDocument == null) { + public void cancelLoadFile(TLRPC.FileLocation location, String ext, boolean deleteFile) { + cancelLoadFile(null, null, null, location, ext, null, deleteFile); + } + + public void cancelLoadFile(String fileName) { + cancelLoadFile(null, null, null, null, null, fileName, true); + } + + public void cancelLoadFiles(ArrayList fileNames) { + for (int a = 0, N = fileNames.size(); a < N; a++) { + cancelLoadFile(null, null, null, null, null, fileNames.get(a), true); + } + } + + private void cancelLoadFile(final TLRPC.Document document, final SecureDocument secureDocument, final WebFile webDocument, final TLRPC.FileLocation location, final String locationExt, String name, boolean deleteFile) { + if (location == null && document == null && webDocument == null && secureDocument == null && TextUtils.isEmpty(name)) { return; } final String fileName; @@ -472,10 +492,7 @@ public class FileLoader extends BaseController { } else if (webDocument != null) { fileName = getAttachFileName(webDocument); } else { - fileName = null; - } - if (fileName == null) { - return; + fileName = name; } loadOperationPathsUI.remove(fileName); fileLoaderQueue.postRunnable(() -> { @@ -491,7 +508,7 @@ public class FileLoader extends BaseController { if (queueType == QUEUE_TYPE_FILE) { activeFileLoadOperation.remove(operation); } - operation.cancel(); + operation.cancel(deleteFile); } }); } @@ -595,33 +612,29 @@ public class FileLoader extends BaseController { int queueType = operation.getQueueType(); LinkedList downloadQueue = getLoadOperationQueue(datacenterId, queueType); SparseIntArray count = getLoadOperationCount(queueType); - if (downloadQueue != null) { - int index = downloadQueue.indexOf(operation); - if (index >= 0) { - downloadQueue.remove(index); - if (stream != null) { - if (operation.start(stream, streamOffset, streamPriority)) { - count.put(datacenterId, count.get(datacenterId) + 1); + int index = downloadQueue.indexOf(operation); + if (index >= 0) { + downloadQueue.remove(index); + if (stream != null) { + if (operation.start(stream, streamOffset, streamPriority)) { + count.put(datacenterId, count.get(datacenterId) + 1); + } + if (queueType == QUEUE_TYPE_FILE) { + if (operation.wasStarted() && !activeFileLoadOperation.contains(operation)) { + pauseCurrentFileLoadOperations(operation); + activeFileLoadOperation.add(operation); } - if (queueType == QUEUE_TYPE_FILE) { - if (operation.wasStarted() && !activeFileLoadOperation.contains(operation)) { - if (stream != null) { - pauseCurrentFileLoadOperations(operation); - } - activeFileLoadOperation.add(operation); - } - } - } else { - downloadQueue.add(0, operation); } } else { - if (stream != null) { - pauseCurrentFileLoadOperations(operation); - } - operation.start(stream, streamOffset, streamPriority); - if (queueType == QUEUE_TYPE_FILE && !activeFileLoadOperation.contains(operation)) { - activeFileLoadOperation.add(operation); - } + downloadQueue.add(0, operation); + } + } else { + if (stream != null) { + pauseCurrentFileLoadOperations(operation); + } + operation.start(stream, streamOffset, streamPriority); + if (queueType == QUEUE_TYPE_FILE && !activeFileLoadOperation.contains(operation)) { + activeFileLoadOperation.add(operation); } } } @@ -632,14 +645,6 @@ public class FileLoader extends BaseController { File tempDir = getDirectory(MEDIA_DIR_CACHE); File storeDir = tempDir; int type = MEDIA_DIR_CACHE; - int queueType; - if (type == MEDIA_DIR_AUDIO) { - queueType = QUEUE_TYPE_AUDIO; - } else if (secureDocument != null || location != null && (imageLocation == null || imageLocation.imageType != IMAGE_TYPE_ANIMATION) || MessageObject.isImageWebDocument(webDocument)) { - queueType = QUEUE_TYPE_IMAGE; - } else { - queueType = QUEUE_TYPE_FILE; - } if (secureDocument != null) { operation = new FileLoadOperation(secureDocument); @@ -660,7 +665,9 @@ public class FileLoader extends BaseController { } } else if (webDocument != null) { operation = new FileLoadOperation(currentAccount, webDocument); - if (MessageObject.isVoiceWebDocument(webDocument)) { + if (webDocument.location != null) { + type = MEDIA_DIR_CACHE; + } else if (MessageObject.isVoiceWebDocument(webDocument)) { type = MEDIA_DIR_AUDIO; } else if (MessageObject.isVideoWebDocument(webDocument)) { type = MEDIA_DIR_VIDEO; @@ -670,6 +677,14 @@ public class FileLoader extends BaseController { type = MEDIA_DIR_DOCUMENT; } } + int queueType; + if (type == MEDIA_DIR_AUDIO) { + queueType = QUEUE_TYPE_AUDIO; + } else if (secureDocument != null || location != null && (imageLocation == null || imageLocation.imageType != IMAGE_TYPE_ANIMATION) || MessageObject.isImageWebDocument(webDocument)) { + queueType = QUEUE_TYPE_IMAGE; + } else { + queueType = QUEUE_TYPE_FILE; + } if (cacheType == 0 || cacheType == 10) { storeDir = getDirectory(type); } else if (cacheType == 2) { @@ -889,8 +904,6 @@ public class FileLoader extends BaseController { return getAttachFileName(sizeFull); } } - } else if (message.media instanceof TLRPC.TL_messageMediaInvoice) { - return getAttachFileName(((TLRPC.TL_messageMediaInvoice) message.media).photo); } } else if (message.media instanceof TLRPC.TL_messageMediaInvoice) { TLRPC.WebDocument document = ((TLRPC.TL_messageMediaInvoice) message.media).photo; @@ -976,7 +989,7 @@ public class FileLoader extends BaseController { } } else if (attach instanceof TLRPC.Photo) { TLRPC.PhotoSize photoSize = getClosestPhotoSizeWithSize(((TLRPC.Photo) attach).sizes, AndroidUtilities.getPhotoSize()); - return getPathToAttach(photoSize, ext, forceCache); + return getPathToAttach(photoSize, ext, false); } else if (attach instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize photoSize = (TLRPC.PhotoSize) attach; if (photoSize instanceof TLRPC.TL_photoStrippedSize) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java index 329353853..0f9f6fc0a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileRefController.java @@ -493,7 +493,7 @@ public class FileRefController extends BaseController { TLRPC.TL_inputMediaPhoto mediaPhoto = (TLRPC.TL_inputMediaPhoto) req.media; mediaPhoto.id.file_reference = file_reference; } - AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null, (Boolean) requester.args[6])); + AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null, null, (Boolean) requester.args[6])); } else if (requester.args[0] instanceof TLRPC.TL_messages_editMessage) { TLRPC.TL_messages_editMessage req = (TLRPC.TL_messages_editMessage) requester.args[0]; if (req.media instanceof TLRPC.TL_inputMediaDocument) { @@ -503,7 +503,7 @@ public class FileRefController extends BaseController { TLRPC.TL_inputMediaPhoto mediaPhoto = (TLRPC.TL_inputMediaPhoto) req.media; mediaPhoto.id.file_reference = file_reference; } - AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null, (Boolean) requester.args[6])); + AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) requester.args[0], (MessageObject) requester.args[1], (String) requester.args[2], (SendMessagesHelper.DelayedMessage) requester.args[3], (Boolean) requester.args[4], (SendMessagesHelper.DelayedMessage) requester.args[5], null, null, (Boolean) requester.args[6])); } else if (requester.args[0] instanceof TLRPC.TL_messages_saveGif) { TLRPC.TL_messages_saveGif req = (TLRPC.TL_messages_saveGif) requester.args[0]; req.id.file_reference = file_reference; @@ -554,7 +554,7 @@ public class FileRefController extends BaseController { AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequestMulti(req, (ArrayList) objects[1], (ArrayList) objects[2], null, (SendMessagesHelper.DelayedMessage) objects[4], (Boolean) objects[5])); } } else if (args[0] instanceof TLRPC.TL_messages_sendMedia || args[0] instanceof TLRPC.TL_messages_editMessage) { - AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) args[0], (MessageObject) args[1], (String) args[2], (SendMessagesHelper.DelayedMessage) args[3], (Boolean) args[4], (SendMessagesHelper.DelayedMessage) args[5], null, (Boolean) args[6])); + AndroidUtilities.runOnUIThread(() -> getSendMessagesHelper().performSendMessageRequest((TLObject) args[0], (MessageObject) args[1], (String) args[2], (SendMessagesHelper.DelayedMessage) args[3], (Boolean) args[4], (SendMessagesHelper.DelayedMessage) args[5], null, null, (Boolean) args[6])); } else if (args[0] instanceof TLRPC.TL_messages_saveGif) { TLRPC.TL_messages_saveGif req = (TLRPC.TL_messages_saveGif) args[0]; //do nothing diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java index d6a9da8cb..732416a44 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java @@ -617,9 +617,6 @@ public class FileUploadOperation { startUploadRequest(); } } else { - if (finalRequest != null) { - FileLog.e("23123"); - } state = 4; delegate.didFailedUploadingFile(FileUploadOperation.this); cleanup(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java index 2d3e316b5..c586ed6e0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java @@ -339,7 +339,7 @@ public class GcmPushListenerService extends FirebaseMessagingService { name = args[1]; } } else if (loc_key.startsWith("PINNED_")) { - supergroup = isGroup; + supergroup = channel_id != 0; pinned = true; } else if (loc_key.startsWith("CHANNEL_")) { channel = true; @@ -469,6 +469,16 @@ public class GcmPushListenerService extends FirebaseMessagingService { localMessage = true; break; } + case "MESSAGE_PLAYLIST": { + messageText = LocaleController.formatString("NotificationMessageFew", R.string.NotificationMessageFew, args[0], LocaleController.formatPluralString("MusicFiles", Utilities.parseInt(args[1]))); + localMessage = true; + break; + } + case "MESSAGE_DOCS": { + messageText = LocaleController.formatString("NotificationMessageFew", R.string.NotificationMessageFew, args[0], LocaleController.formatPluralString("Files", Utilities.parseInt(args[1]))); + localMessage = true; + break; + } case "MESSAGES": { messageText = LocaleController.formatString("NotificationMessageAlbum", R.string.NotificationMessageAlbum, args[0]); localMessage = true; @@ -564,6 +574,16 @@ public class GcmPushListenerService extends FirebaseMessagingService { localMessage = true; break; } + case "CHANNEL_MESSAGE_PLAYLIST": { + messageText = LocaleController.formatString("ChannelMessageFew", R.string.ChannelMessageFew, args[0], LocaleController.formatPluralString("MusicFiles", Utilities.parseInt(args[1]))); + localMessage = true; + break; + } + case "CHANNEL_MESSAGE_DOCS": { + messageText = LocaleController.formatString("ChannelMessageFew", R.string.ChannelMessageFew, args[0], LocaleController.formatPluralString("Files", Utilities.parseInt(args[1]))); + localMessage = true; + break; + } case "CHANNEL_MESSAGES": { messageText = LocaleController.formatString("ChannelMessageAlbum", R.string.ChannelMessageAlbum, args[0]); localMessage = true; @@ -710,152 +730,234 @@ public class GcmPushListenerService extends FirebaseMessagingService { localMessage = true; break; } + case "CHAT_MESSAGE_PLAYLIST": { + messageText = LocaleController.formatString("NotificationGroupFew", R.string.NotificationGroupFew, args[0], args[1], LocaleController.formatPluralString("MusicFiles", Utilities.parseInt(args[2]))); + localMessage = true; + break; + } + case "CHAT_MESSAGE_DOCS": { + messageText = LocaleController.formatString("NotificationGroupFew", R.string.NotificationGroupFew, args[0], args[1], LocaleController.formatPluralString("Files", Utilities.parseInt(args[2]))); + localMessage = true; + break; + } case "CHAT_MESSAGES": { messageText = LocaleController.formatString("NotificationGroupAlbum", R.string.NotificationGroupAlbum, args[0], args[1]); localMessage = true; break; } case "PINNED_TEXT": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedText", R.string.NotificationActionPinnedText, args[0], args[1], args[2]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedTextChannel", R.string.NotificationActionPinnedTextChannel, args[0], args[1]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedText", R.string.NotificationActionPinnedText, args[0], args[1], args[2]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedTextChannel", R.string.NotificationActionPinnedTextChannel, args[0], args[1]); + } } break; } case "PINNED_NOTEXT": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedNoTextUser", R.string.NotificationActionPinnedNoTextUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, args[0]); + } } break; } case "PINNED_PHOTO": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedPhoto", R.string.NotificationActionPinnedPhoto, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedPhotoUser", R.string.NotificationActionPinnedPhotoUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedPhotoChannel", R.string.NotificationActionPinnedPhotoChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedPhoto", R.string.NotificationActionPinnedPhoto, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedPhotoChannel", R.string.NotificationActionPinnedPhotoChannel, args[0]); + } } break; } case "PINNED_VIDEO": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedVideo", R.string.NotificationActionPinnedVideo, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedVideoUser", R.string.NotificationActionPinnedVideoUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedVideoChannel", R.string.NotificationActionPinnedVideoChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedVideo", R.string.NotificationActionPinnedVideo, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedVideoChannel", R.string.NotificationActionPinnedVideoChannel, args[0]); + } } break; } case "PINNED_ROUND": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedRound", R.string.NotificationActionPinnedRound, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedRoundUser", R.string.NotificationActionPinnedRoundUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedRoundChannel", R.string.NotificationActionPinnedRoundChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedRound", R.string.NotificationActionPinnedRound, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedRoundChannel", R.string.NotificationActionPinnedRoundChannel, args[0]); + } } break; } case "PINNED_DOC": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedFile", R.string.NotificationActionPinnedFile, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedFileUser", R.string.NotificationActionPinnedFileUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedFileChannel", R.string.NotificationActionPinnedFileChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedFile", R.string.NotificationActionPinnedFile, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedFileChannel", R.string.NotificationActionPinnedFileChannel, args[0]); + } } break; } case "PINNED_STICKER": { - if (isGroup) { - if (args.length > 2 && !TextUtils.isEmpty(args[2])) { - messageText = LocaleController.formatString("NotificationActionPinnedStickerEmoji", R.string.NotificationActionPinnedStickerEmoji, args[0], args[2], args[1]); + if (dialogId > 0) { + if (args.length > 1 && !TextUtils.isEmpty(args[1])) { + messageText = LocaleController.formatString("NotificationActionPinnedStickerEmojiUser", R.string.NotificationActionPinnedStickerEmojiUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedSticker", R.string.NotificationActionPinnedSticker, args[0], args[1]); + messageText = LocaleController.formatString("NotificationActionPinnedStickerUser", R.string.NotificationActionPinnedStickerUser, args[0]); } } else { - if (args.length > 1 && !TextUtils.isEmpty(args[1])) { - messageText = LocaleController.formatString("NotificationActionPinnedStickerEmojiChannel", R.string.NotificationActionPinnedStickerEmojiChannel, args[0], args[1]); + if (isGroup) { + if (args.length > 2 && !TextUtils.isEmpty(args[2])) { + messageText = LocaleController.formatString("NotificationActionPinnedStickerEmoji", R.string.NotificationActionPinnedStickerEmoji, args[0], args[2], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedSticker", R.string.NotificationActionPinnedSticker, args[0], args[1]); + } } else { - messageText = LocaleController.formatString("NotificationActionPinnedStickerChannel", R.string.NotificationActionPinnedStickerChannel, args[0]); + if (args.length > 1 && !TextUtils.isEmpty(args[1])) { + messageText = LocaleController.formatString("NotificationActionPinnedStickerEmojiChannel", R.string.NotificationActionPinnedStickerEmojiChannel, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedStickerChannel", R.string.NotificationActionPinnedStickerChannel, args[0]); + } } } break; } case "PINNED_AUDIO": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedVoice", R.string.NotificationActionPinnedVoice, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedVoiceUser", R.string.NotificationActionPinnedVoiceUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedVoice", R.string.NotificationActionPinnedVoice, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, args[0]); + } } break; } case "PINNED_CONTACT": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedContact2", R.string.NotificationActionPinnedContact2, args[0], args[2], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedContactUser", R.string.NotificationActionPinnedContactUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedContactChannel2", R.string.NotificationActionPinnedContactChannel2, args[0], args[1]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedContact2", R.string.NotificationActionPinnedContact2, args[0], args[2], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedContactChannel2", R.string.NotificationActionPinnedContactChannel2, args[0], args[1]); + } } break; } case "PINNED_QUIZ": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedQuiz2", R.string.NotificationActionPinnedQuiz2, args[0], args[2], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedQuizUser", R.string.NotificationActionPinnedQuizUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedQuizChannel2", R.string.NotificationActionPinnedQuizChannel2, args[0], args[1]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedQuiz2", R.string.NotificationActionPinnedQuiz2, args[0], args[2], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedQuizChannel2", R.string.NotificationActionPinnedQuizChannel2, args[0], args[1]); + } } break; } case "PINNED_POLL": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedPoll2", R.string.NotificationActionPinnedPoll2, args[0], args[2], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedPollUser", R.string.NotificationActionPinnedPollUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedPollChannel2", R.string.NotificationActionPinnedPollChannel2, args[0], args[1]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedPoll2", R.string.NotificationActionPinnedPoll2, args[0], args[2], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedPollChannel2", R.string.NotificationActionPinnedPollChannel2, args[0], args[1]); + } } break; } case "PINNED_GEO": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedGeo", R.string.NotificationActionPinnedGeo, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedGeoUser", R.string.NotificationActionPinnedGeoUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedGeoChannel", R.string.NotificationActionPinnedGeoChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedGeo", R.string.NotificationActionPinnedGeo, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedGeoChannel", R.string.NotificationActionPinnedGeoChannel, args[0]); + } } break; } case "PINNED_GEOLIVE": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedGeoLive", R.string.NotificationActionPinnedGeoLive, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedGeoLiveUser", R.string.NotificationActionPinnedGeoLiveUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedGeoLiveChannel", R.string.NotificationActionPinnedGeoLiveChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedGeoLive", R.string.NotificationActionPinnedGeoLive, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedGeoLiveChannel", R.string.NotificationActionPinnedGeoLiveChannel, args[0]); + } } break; } case "PINNED_GAME": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedGame", R.string.NotificationActionPinnedGame, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedGameUser", R.string.NotificationActionPinnedGameUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedGameChannel", R.string.NotificationActionPinnedGameChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedGame", R.string.NotificationActionPinnedGame, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedGameChannel", R.string.NotificationActionPinnedGameChannel, args[0]); + } } break; } case "PINNED_GAME_SCORE": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedGameScore", R.string.NotificationActionPinnedGameScore, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedGameScoreUser", R.string.NotificationActionPinnedGameScoreUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedGameScoreChannel", R.string.NotificationActionPinnedGameScoreChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedGameScore", R.string.NotificationActionPinnedGameScore, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedGameScoreChannel", R.string.NotificationActionPinnedGameScoreChannel, args[0]); + } } break; } case "PINNED_INVOICE": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedInvoice", R.string.NotificationActionPinnedInvoice, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedInvoiceUser", R.string.NotificationActionPinnedInvoiceUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedInvoiceChannel", R.string.NotificationActionPinnedInvoiceChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedInvoice", R.string.NotificationActionPinnedInvoice, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedInvoiceChannel", R.string.NotificationActionPinnedInvoiceChannel, args[0]); + } } break; } case "PINNED_GIF": { - if (isGroup) { - messageText = LocaleController.formatString("NotificationActionPinnedGif", R.string.NotificationActionPinnedGif, args[0], args[1]); + if (dialogId > 0) { + messageText = LocaleController.formatString("NotificationActionPinnedGifUser", R.string.NotificationActionPinnedGifUser, args[0], args[1]); } else { - messageText = LocaleController.formatString("NotificationActionPinnedGifChannel", R.string.NotificationActionPinnedGifChannel, args[0]); + if (isGroup) { + messageText = LocaleController.formatString("NotificationActionPinnedGif", R.string.NotificationActionPinnedGif, args[0], args[1]); + } else { + messageText = LocaleController.formatString("NotificationActionPinnedGifChannel", R.string.NotificationActionPinnedGifChannel, args[0]); + } } break; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java index 5ac0319b3..ca50e83aa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -37,6 +37,7 @@ import org.telegram.ui.Cells.ChatMessageCell; import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.Point; import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.SlotsDrawable; import org.telegram.ui.Components.SvgHelper; import org.telegram.ui.Components.ThemePreviewDrawable; @@ -830,7 +831,11 @@ public class ImageLoader { } RLottieDrawable lottieDrawable; if (diceEmoji != null) { - lottieDrawable = new RLottieDrawable(diceEmoji, w, h); + if ("\uD83C\uDFB0".equals(diceEmoji)) { + lottieDrawable = new SlotsDrawable(diceEmoji, w, h); + } else { + lottieDrawable = new RLottieDrawable(diceEmoji, w, h); + } } else { lottieDrawable = new RLottieDrawable(cacheImage.finalFilePath, w, h, precache, limitFps, colors); } @@ -1037,7 +1042,8 @@ public class ImageLoader { int photoW2 = opts.outWidth; int photoH2 = opts.outHeight; opts.inJustDecodeBounds = false; - float scaleFactor = Math.max(photoW2 / 200, photoH2 / 200); + int screenSize = Math.max(66, Math.min(AndroidUtilities.getRealScreenSize().x, AndroidUtilities.getRealScreenSize().y)); + float scaleFactor = (Math.min(photoH2, photoW2) / (float) screenSize) * 6f; if (scaleFactor < 1) { scaleFactor = 1; } @@ -1045,7 +1051,7 @@ public class ImageLoader { int sample = 1; do { sample *= 2; - } while (sample * 2 < scaleFactor); + } while (sample * 2 <= scaleFactor); opts.inSampleSize = sample; } else { opts.inSampleSize = (int) scaleFactor; @@ -2339,7 +2345,7 @@ public class ImageLoader { } else if (BuildVars.DEBUG_PRIVATE_VERSION) { String name = FileLoader.getDocumentFileName(imageLocation.document); if (name.endsWith(".svg")) { - img.imageType = FileLoader.IMAGE_TYPE_SVG_WHITE; + img.imageType = FileLoader.IMAGE_TYPE_SVG; } } } @@ -2373,7 +2379,7 @@ public class ImageLoader { } else if (BuildVars.DEBUG_PRIVATE_VERSION) { String name = FileLoader.getDocumentFileName(imageLocation.document); if (name.endsWith(".svg")) { - img.imageType = FileLoader.IMAGE_TYPE_SVG_WHITE; + img.imageType = FileLoader.IMAGE_TYPE_SVG; } } fileSize = document.size; @@ -2462,6 +2468,37 @@ public class ImageLoader { }); } + public void preloadArtwork(String athumbUrl) { + imageLoadQueue.postRunnable(() -> { + String ext = getHttpUrlExtension(athumbUrl, "jpg"); + String url = Utilities.MD5(athumbUrl) + "." + ext; + File cacheFile = new File(FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE), url); + if (cacheFile.exists()) { + return; + } + ImageLocation imageLocation = ImageLocation.getForPath(athumbUrl); + CacheImage img = new CacheImage(); + img.type = ImageReceiver.TYPE_THUMB; + img.key = Utilities.MD5(athumbUrl); + img.filter = null; + img.imageLocation = imageLocation; + img.ext = ext; + img.parentObject = null; + if (imageLocation.imageType != 0) { + img.imageType = imageLocation.imageType; + } + img.url = url; + imageLoadingByUrl.put(url, img); + String file = Utilities.MD5(imageLocation.path); + File cacheDir = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE); + img.tempFilePath = new File(cacheDir, file + "_temp.jpg"); + img.finalFilePath = cacheFile; + img.artworkTask = new ArtworkLoadTask(img); + artworkTasks.add(img.artworkTask); + runArtworkTasks(false); + }); + } + public void loadImageForImageReceiver(ImageReceiver imageReceiver) { if (imageReceiver == null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java index b1aacd2e5..82fdbd302 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -620,7 +620,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } else if (bitmap instanceof RLottieDrawable) { RLottieDrawable fileDrawable = (RLottieDrawable) bitmap; fileDrawable.addParentView(parentView); - if (allowStartLottieAnimation && currentOpenedLayerFlags == 0) { + if (allowStartLottieAnimation && (!fileDrawable.isHeavyDrawable() || currentOpenedLayerFlags == 0)) { fileDrawable.start(); } fileDrawable.setAllowDecodeSingleFrame(true); @@ -749,11 +749,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg setImage(temp.mediaLocation, temp.mediaFilter, temp.imageLocation, temp.imageFilter, temp.thumbLocation, temp.thumbFilter, temp.thumb, temp.size, temp.ext, temp.parentObject, temp.cacheType); temp.clear(); setImageBackup = temp; - if (allowStartLottieAnimation && currentOpenedLayerFlags == 0) { - RLottieDrawable lottieDrawable = getLottieAnimation(); - if (lottieDrawable != null) { - lottieDrawable.start(); - } + RLottieDrawable lottieDrawable = getLottieAnimation(); + if (lottieDrawable != null && allowStartLottieAnimation && (!lottieDrawable.isHeavyDrawable() || currentOpenedLayerFlags == 0)) { + lottieDrawable.start(); } return true; } @@ -769,11 +767,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg if (setBackupImage()) { return true; } - if (allowStartLottieAnimation && currentOpenedLayerFlags == 0) { - RLottieDrawable lottieDrawable = getLottieAnimation(); - if (lottieDrawable != null) { - lottieDrawable.start(); - } + RLottieDrawable lottieDrawable = getLottieAnimation(); + if (lottieDrawable != null && allowStartLottieAnimation && (!lottieDrawable.isHeavyDrawable() || currentOpenedLayerFlags == 0)) { + lottieDrawable.start(); } if (NotificationCenter.getGlobalInstance().isAnimationInProgress()) { didReceivedNotification(NotificationCenter.stopAllHeavyOperations, currentAccount, 512); @@ -1122,6 +1118,14 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } } + public void skipDraw() { + RLottieDrawable lottieDrawable = getLottieAnimation(); + if (lottieDrawable != null) { + lottieDrawable.setCurrentParentView(parentView); + lottieDrawable.updateCurrentFrame(); + } + } + public boolean draw(Canvas canvas) { try { Drawable drawable = null; @@ -1890,7 +1894,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg } else if (drawable instanceof RLottieDrawable) { RLottieDrawable fileDrawable = (RLottieDrawable) drawable; fileDrawable.addParentView(parentView); - if (allowStartLottieAnimation && currentOpenedLayerFlags == 0) { + if (allowStartLottieAnimation && (!fileDrawable.isHeavyDrawable() || currentOpenedLayerFlags == 0)) { fileDrawable.start(); } fileDrawable.setAllowDecodeSingleFrame(true); @@ -2016,7 +2020,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg currentOpenedLayerFlags |= layer; if (currentOpenedLayerFlags != 0) { RLottieDrawable lottieDrawable = getLottieAnimation(); - if (lottieDrawable != null) { + if (lottieDrawable != null && lottieDrawable.isHeavyDrawable()) { lottieDrawable.stop(); } } @@ -2028,7 +2032,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg currentOpenedLayerFlags &=~ layer; if (currentOpenedLayerFlags == 0) { RLottieDrawable lottieDrawable = getLottieAnimation(); - if (allowStartLottieAnimation && lottieDrawable != null) { + if (allowStartLottieAnimation && lottieDrawable != null && lottieDrawable.isHeavyDrawable()) { lottieDrawable.start(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java index 33c930458..ebacc44bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -261,9 +261,9 @@ public class LocaleController { "nl", "nn", "no", "sv", "af", "bg", "bn", "ca", "eu", "fur", "fy", "gu", "ha", "is", "ku", "lb", "ml", "mr", "nah", "ne", "om", "or", "pa", "pap", "ps", "so", "sq", "sw", "ta", "te", "tk", "ur", "zu", "mn", "gsw", "chr", "rm", "pt", "an", "ast"}, new PluralRules_One()); - addRules(new String[]{"cs", "sk"}, new PluralRules_Czech()); + addRules(new String[]{"cs", "sk", "sr", "hr", "bs"}, new PluralRules_Czech()); addRules(new String[]{"ff", "fr", "kab"}, new PluralRules_French()); - addRules(new String[]{"hr", "ru", "sr", "uk", "be", "bs", "sh"}, new PluralRules_Balkan()); + addRules(new String[]{"ru", "uk", "be", "sh"}, new PluralRules_Balkan()); addRules(new String[]{"lv"}, new PluralRules_Latvian()); addRules(new String[]{"lt"}, new PluralRules_Lithuanian()); addRules(new String[]{"pl"}, new PluralRules_Polish()); @@ -958,7 +958,7 @@ public class LocaleController { currentLocale = newLocale; currentLocaleInfo = localeInfo; - if (currentLocaleInfo != null && !TextUtils.isEmpty(currentLocaleInfo.pluralLangCode)) { + if (!TextUtils.isEmpty(currentLocaleInfo.pluralLangCode)) { currentPluralRules = allRules.get(currentLocaleInfo.pluralLangCode); } if (currentPluralRules == null) { @@ -1005,12 +1005,21 @@ public class LocaleController { } private String getStringInternal(String key, int res) { + return getStringInternal(key, null, res); + } + + private String getStringInternal(String key, String fallback, int res) { String value = BuildVars.USE_CLOUD_STRINGS ? localeValues.get(key) : null; if (value == null) { - try { - value = ApplicationLoader.applicationContext.getString(res); - } catch (Exception e) { - FileLog.e(e); + if (BuildVars.USE_CLOUD_STRINGS && fallback != null) { + value = localeValues.get(fallback); + } + if (value == null) { + try { + value = ApplicationLoader.applicationContext.getString(res); + } catch (Exception e) { + FileLog.e(e); + } } } if (value == null) { @@ -1034,6 +1043,10 @@ public class LocaleController { return getInstance().getStringInternal(key, res); } + public static String getString(String key, String fallback, int res) { + return getInstance().getStringInternal(key, fallback, res); + } + public static String getString(String key) { if (TextUtils.isEmpty(key)) { return "LOC_ERR:" + key; @@ -1052,7 +1065,7 @@ public class LocaleController { String param = getInstance().stringForQuantity(getInstance().currentPluralRules.quantityForNumber(plural)); param = key + "_" + param; int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); - return getString(param, resourceId); + return getString(param, key + "_other", resourceId); } public static String formatPluralString(String key, int plural) { @@ -1062,7 +1075,7 @@ public class LocaleController { String param = getInstance().stringForQuantity(getInstance().currentPluralRules.quantityForNumber(plural)); param = key + "_" + param; int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); - return formatString(param, resourceId, plural); + return formatString(param, key + "_other", resourceId, plural); } public static String formatPluralStringComma(String key, int plural) { @@ -1078,6 +1091,9 @@ public class LocaleController { } String value = BuildVars.USE_CLOUD_STRINGS ? getInstance().localeValues.get(param) : null; + if (value == null) { + value = BuildVars.USE_CLOUD_STRINGS ? getInstance().localeValues.get(key + "_other") : null; + } if (value == null) { int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); value = ApplicationLoader.applicationContext.getString(resourceId); @@ -1096,10 +1112,19 @@ public class LocaleController { } public static String formatString(String key, int res, Object... args) { + return formatString(key, null, res, args); + } + + public static String formatString(String key, String fallback, int res, Object... args) { try { String value = BuildVars.USE_CLOUD_STRINGS ? getInstance().localeValues.get(key) : null; if (value == null) { - value = ApplicationLoader.applicationContext.getString(res); + if (BuildVars.USE_CLOUD_STRINGS && fallback != null) { + value = getInstance().localeValues.get(fallback); + } + if (value == null) { + value = ApplicationLoader.applicationContext.getString(res); + } } if (getInstance().currentLocale != null) { @@ -1866,12 +1891,10 @@ public class LocaleController { valuesToSet.putAll(getLocaleFileStrings(localeInfo.getPathToFile())); } AndroidUtilities.runOnUIThread(() -> { - if (localeInfo != null) { - if (type == 0) { - localeInfo.version = difference.version; - } else { - localeInfo.baseVersion = difference.version; - } + if (type == 0) { + localeInfo.version = difference.version; + } else { + localeInfo.baseVersion = difference.version; } saveOtherLanguages(); try { @@ -1890,34 +1913,31 @@ public class LocaleController { } else { newLocale = new Locale(args[0], args[1]); } - if (newLocale != null) { - languageOverride = localeInfo.shortName; + languageOverride = localeInfo.shortName; - SharedPreferences preferences = MessagesController.getGlobalMainSettings(); - SharedPreferences.Editor editor = preferences.edit(); - editor.putString("language", localeInfo.getKey()); - editor.apply(); + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("language", localeInfo.getKey()); + editor.apply(); + + localeValues = valuesToSet; + currentLocale = newLocale; + currentLocaleInfo = localeInfo; + if (!TextUtils.isEmpty(currentLocaleInfo.pluralLangCode)) { + currentPluralRules = allRules.get(currentLocaleInfo.pluralLangCode); } - if (newLocale != null) { - localeValues = valuesToSet; - currentLocale = newLocale; - currentLocaleInfo = localeInfo; - if (currentLocaleInfo != null && !TextUtils.isEmpty(currentLocaleInfo.pluralLangCode)) { - currentPluralRules = allRules.get(currentLocaleInfo.pluralLangCode); - } + if (currentPluralRules == null) { + currentPluralRules = allRules.get(currentLocale.getLanguage()); if (currentPluralRules == null) { - currentPluralRules = allRules.get(currentLocale.getLanguage()); - if (currentPluralRules == null) { - currentPluralRules = allRules.get("en"); - } + currentPluralRules = allRules.get("en"); } - changingConfiguration = true; - Locale.setDefault(currentLocale); - Configuration config = new Configuration(); - config.locale = currentLocale; - ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); - changingConfiguration = false; } + changingConfiguration = true; + Locale.setDefault(currentLocale); + Configuration config = new Configuration(); + config.locale = currentLocale; + ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); + changingConfiguration = false; } } catch (Exception e) { FileLog.e(e); @@ -2005,7 +2025,7 @@ public class LocaleController { } private void applyRemoteLanguage(LocaleInfo localeInfo, String langCode, boolean force, final int currentAccount) { - if (localeInfo == null || localeInfo != null && !localeInfo.isRemote() && !localeInfo.isUnofficial()) { + if (localeInfo == null || !localeInfo.isRemote() && !localeInfo.isUnofficial()) { return; } if (localeInfo.hasBaseLang() && (langCode == null || langCode.equals(localeInfo.baseLangCode))) { @@ -2936,32 +2956,49 @@ public class LocaleController { useImperialSystemType = null; } - public static String formatDistance(float distance, int type) { - if (useImperialSystemType == null) { - if (SharedConfig.distanceSystemType == 0) { - try { - TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); - if (telephonyManager != null) { - String country = telephonyManager.getSimCountryIso().toUpperCase(); - useImperialSystemType = "US".equals(country) || "GB".equals(country) || "MM".equals(country) || "LR".equals(country); - } - } catch (Exception e) { - useImperialSystemType = false; - FileLog.e(e); - } - } else { - useImperialSystemType = SharedConfig.distanceSystemType == 2; - } + public static boolean getUseImperialSystemType() { + ensureImperialSystemInit(); + return useImperialSystemType; + } + + public static void ensureImperialSystemInit() { + if (useImperialSystemType != null) { + return; } - if (useImperialSystemType) { + if (SharedConfig.distanceSystemType == 0) { + try { + TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null) { + String country = telephonyManager.getSimCountryIso().toUpperCase(); + useImperialSystemType = "US".equals(country) || "GB".equals(country) || "MM".equals(country) || "LR".equals(country); + } + } catch (Exception e) { + useImperialSystemType = false; + FileLog.e(e); + } + } else { + useImperialSystemType = SharedConfig.distanceSystemType == 2; + } + } + + public static String formatDistance(float distance, int type) { + return formatDistance(distance, type, null); + } + + public static String formatDistance(float distance, int type, Boolean useImperial) { + ensureImperialSystemInit(); + boolean imperial = useImperial != null && useImperial || useImperial == null && useImperialSystemType; + if (imperial) { distance *= 3.28084f; if (distance < 1000) { switch (type) { case 0: return formatString("FootsAway", R.string.FootsAway, String.format("%d", (int) Math.max(1, distance))); case 1: - default: return formatString("FootsFromYou", R.string.FootsFromYou, String.format("%d", (int) Math.max(1, distance))); + case 2: + default: + return formatString("FootsShort", R.string.FootsShort, String.format("%d", (int) Math.max(1, distance))); } } else { String arg; @@ -2974,8 +3011,10 @@ public class LocaleController { case 0: return formatString("MilesAway", R.string.MilesAway, arg); case 1: - default: return formatString("MilesFromYou", R.string.MilesFromYou, arg); + default: + case 2: + return formatString("MilesShort", R.string.MilesShort, arg); } } @@ -2985,8 +3024,10 @@ public class LocaleController { case 0: return formatString("MetersAway2", R.string.MetersAway2, String.format("%d", (int) Math.max(1, distance))); case 1: - default: return formatString("MetersFromYou2", R.string.MetersFromYou2, String.format("%d", (int) Math.max(1, distance))); + case 2: + default: + return formatString("MetersShort", R.string.MetersShort, String.format("%d", (int) Math.max(1, distance))); } } else { String arg; @@ -2999,8 +3040,10 @@ public class LocaleController { case 0: return formatString("KMetersAway2", R.string.KMetersAway2, arg); case 1: - default: return formatString("KMetersFromYou2", R.string.KMetersFromYou2, arg); + case 2: + default: + return formatString("KMetersShort", R.string.KMetersShort, arg); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java index 896268565..376544e97 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocationController.java @@ -91,6 +91,8 @@ public class LocationController extends BaseController implements NotificationCe public int stopTime; public int period; public int account; + public int proximityMeters; + public int lastSentProximityMeters; public MessageObject messageObject; } @@ -174,6 +176,11 @@ public class LocationController extends BaseController implements NotificationCe if (!replaced) { messages.add(messageObject.messageOwner); } + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) { + int lowerId = (int) messageObject.getDialogId(); + if (lowerId > 0) { + setProximityLocation(messageObject.getDialogId(), 0, false); + } } } if (added) { @@ -255,7 +262,7 @@ public class LocationController extends BaseController implements NotificationCe float[] result = new float[1]; for (int a = 0; a < sharingLocations.size(); a++) { final SharingLocationInfo info = sharingLocations.get(a); - if (info.messageObject.messageOwner.media != null && info.messageObject.messageOwner.media.geo != null) { + if (info.messageObject.messageOwner.media != null && info.messageObject.messageOwner.media.geo != null && info.lastSentProximityMeters == info.proximityMeters) { int messageDate = info.messageObject.messageOwner.edit_date != 0 ? info.messageObject.messageOwner.edit_date : info.messageObject.messageOwner.date; TLRPC.GeoPoint point = info.messageObject.messageOwner.media.geo; if (Math.abs(date - messageDate) < 10) { @@ -274,6 +281,16 @@ public class LocationController extends BaseController implements NotificationCe req.media.geo_point = new TLRPC.TL_inputGeoPoint(); req.media.geo_point.lat = AndroidUtilities.fixLocationCoord(lastKnownLocation.getLatitude()); req.media.geo_point._long = AndroidUtilities.fixLocationCoord(lastKnownLocation.getLongitude()); + req.media.geo_point.accuracy_radius = (int) lastKnownLocation.getAccuracy(); + if (req.media.geo_point.accuracy_radius != 0) { + req.media.geo_point.flags |= 1; + } + if (info.lastSentProximityMeters != info.proximityMeters) { + req.media.proximity_notification_radius = info.proximityMeters; + req.media.flags |= 8; + } + req.media.heading = getHeading(lastKnownLocation); + req.media.flags |= 4; final int[] reqId = new int[1]; reqId[0] = getConnectionsManager().sendRequest(req, (response, error) -> { if (error != null) { @@ -293,6 +310,9 @@ public class LocationController extends BaseController implements NotificationCe } return; } + if ((req.flags & 8) != 0) { + info.lastSentProximityMeters = req.media.proximity_notification_radius; + } TLRPC.Updates updates = (TLRPC.Updates) response; boolean updated = false; for (int a1 = 0; a1 < updates.updates.size(); a1++) { @@ -439,16 +459,17 @@ public class LocationController extends BaseController implements NotificationCe return cachedNearbyChats; } - protected void addSharingLocation(long did, int mid, int period, TLRPC.Message message) { + protected void addSharingLocation(TLRPC.Message message) { final SharingLocationInfo info = new SharingLocationInfo(); - info.did = did; - info.mid = mid; - info.period = period; + info.did = message.dialog_id; + info.mid = message.id; + info.period = message.media.period; + info.lastSentProximityMeters = info.proximityMeters = message.media.proximity_notification_radius; info.account = currentAccount; info.messageObject = new MessageObject(currentAccount, message, false, false); - info.stopTime = getConnectionsManager().getCurrentTime() + period; - final SharingLocationInfo old = sharingLocationsMap.get(did); - sharingLocationsMap.put(did, info); + info.stopTime = getConnectionsManager().getCurrentTime() + info.period; + final SharingLocationInfo old = sharingLocationsMap.get(info.did); + sharingLocationsMap.put(info.did, info); if (old != null) { sharingLocations.remove(old); } @@ -474,6 +495,41 @@ public class LocationController extends BaseController implements NotificationCe return sharingLocationsMapUI.get(did); } + public boolean setProximityLocation(long did, int meters, boolean broadcast) { + SharingLocationInfo info = sharingLocationsMapUI.get(did); + if (info != null) { + info.proximityMeters = meters; + } + getMessagesStorage().getStorageQueue().postRunnable(() -> { + try { + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("UPDATE sharing_locations SET proximity = ? WHERE uid = ?"); + state.requery(); + state.bindInteger(1, meters); + state.bindLong(2, did); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e(e); + } + }); + if (broadcast) { + Utilities.stageQueue.postRunnable(() -> broadcastLastKnownLocation(true)); + } + return info != null; + } + + public static int getHeading(Location location) { + float val = location.getBearing(); + if (val > 0 && val < 1.0f) { + if (val < 0.5f) { + return 360; + } else { + return 1; + } + } + return (int) val; + } + private void loadSharingLocations() { getMessagesStorage().getStorageQueue().postRunnable(() -> { final ArrayList result = new ArrayList<>(); @@ -482,13 +538,14 @@ public class LocationController extends BaseController implements NotificationCe try { ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT uid, mid, date, period, message FROM sharing_locations WHERE 1"); + SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized("SELECT uid, mid, date, period, message, proximity FROM sharing_locations WHERE 1"); while (cursor.next()) { SharingLocationInfo info = new SharingLocationInfo(); info.did = cursor.longValue(0); info.mid = cursor.intValue(1); info.stopTime = cursor.intValue(2); info.period = cursor.intValue(3); + info.proximityMeters = cursor.intValue(5); info.account = currentAccount; NativeByteBuffer data = cursor.byteBufferValue(4); if (data != null) { @@ -564,7 +621,7 @@ public class LocationController extends BaseController implements NotificationCe if (info == null) { return; } - SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO sharing_locations VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO sharing_locations VALUES(?, ?, ?, ?, ?, ?)"); state.requery(); NativeByteBuffer data = new NativeByteBuffer(info.messageObject.messageOwner.getObjectSize()); @@ -575,6 +632,7 @@ public class LocationController extends BaseController implements NotificationCe state.bindInteger(3, info.stopTime); state.bindInteger(4, info.period); state.bindByteBuffer(5, data); + state.bindInteger(6, info.proximityMeters); state.step(); state.dispose(); @@ -784,7 +842,7 @@ public class LocationController extends BaseController implements NotificationCe return; } ArrayList messages = locationsCache.get(dialogId); - if (messages.isEmpty() || messages == null) { + if (messages == null || messages.isEmpty()) { return; } Integer date = lastReadLocationTime.get(dialogId); @@ -839,9 +897,7 @@ public class LocationController extends BaseController implements NotificationCe callbacks.remove(callback); } if (location == null) { - if (callback != null) { - callback.onLocationAddressAvailable(null, null, null); - } + callback.onLocationAddressAvailable(null, null, null); return; } @@ -946,9 +1002,7 @@ public class LocationController extends BaseController implements NotificationCe final String displayNameFinal = displayName; AndroidUtilities.runOnUIThread(() -> { callbacks.remove(callback); - if (callback != null) { - callback.onLocationAddressAvailable(nameFinal, displayNameFinal, location); - } + callback.onLocationAddressAvailable(nameFinal, displayNameFinal, location); }); }, 300); callbacks.put(callback, fetchLocationRunnable); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java index 3da36d1ae..bfe3503ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocationSharingService.java @@ -94,6 +94,7 @@ public class LocationSharingService extends Service implements NotificationCente } String param; ArrayList infos = getInfos(); + String str; if (infos.size() == 1) { LocationController.SharingLocationInfo info = infos.get(0); int lower_id = (int) info.messageObject.getDialogId(); @@ -101,6 +102,7 @@ public class LocationSharingService extends Service implements NotificationCente if (lower_id > 0) { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(lower_id); param = UserObject.getFirstName(user); + str = LocaleController.getString("AttachLiveLocationIsSharing", R.string.AttachLiveLocationIsSharing); } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_id); if (chat != null) { @@ -108,13 +110,15 @@ public class LocationSharingService extends Service implements NotificationCente } else { param = ""; } + str = LocaleController.getString("AttachLiveLocationIsSharingChat", R.string.AttachLiveLocationIsSharingChat); } } else { param = LocaleController.formatPluralString("Chats", infos.size()); + str = LocaleController.getString("AttachLiveLocationIsSharingChats", R.string.AttachLiveLocationIsSharingChats); } - String str = String.format(LocaleController.getString("AttachLiveLocationIsSharing", R.string.AttachLiveLocationIsSharing), LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation), param); - builder.setTicker(str); - builder.setContentText(str); + String text = String.format(str, LocaleController.getString("AttachLiveLocation", R.string.AttachLiveLocation), param); + builder.setTicker(text); + builder.setContentText(text); if (post) { NotificationManagerCompat.from(ApplicationLoader.applicationContext).notify(6, builder.build()); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java index 91fe72a63..6c6eafd8c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -90,6 +90,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.CountDownLatch; import tw.nekomimi.nekogram.NekoConfig; import tw.nekomimi.nekogram.NekoXConfig; @@ -482,6 +483,8 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, private boolean isPaused = false; private VideoPlayer audioPlayer = null; + private VideoPlayer emojiSoundPlayer = null; + private int emojiSoundPlayerNum = 0; private boolean isStreamingCurrentAudio; private int playerNum; private String shouldSavePositionForCurrentAudio; @@ -2115,10 +2118,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } currentPlaylistNum = index; playMusicAgain = true; - if (playingMessageObject != null) { + MessageObject messageObject = playlist.get(currentPlaylistNum); + if (playingMessageObject != null && !isSamePlayingMessage(messageObject)) { playingMessageObject.resetPlayingProgress(); } - playMessage(playlist.get(currentPlaylistNum)); + playMessage(messageObject); } private void playNextMessageWithoutOrder(boolean byStop) { @@ -2609,6 +2613,91 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, }*/ } + public void playEmojiSound(AccountInstance accountInstance, String emoji, MessagesController.EmojiSound sound, boolean loadOnly) { + if (sound == null) { + return; + } + Utilities.stageQueue.postRunnable(() -> { + TLRPC.Document document = new TLRPC.TL_document(); + document.access_hash = sound.accessHash; + document.id = sound.id; + document.mime_type = "sound/ogg"; + document.file_reference = sound.fileReference; + document.dc_id = accountInstance.getConnectionsManager().getCurrentDatacenterId(); + File file = FileLoader.getPathToAttach(document, true); + if (file.exists()) { + if (loadOnly) { + return; + } + AndroidUtilities.runOnUIThread(() -> { + try { + int tag = ++emojiSoundPlayerNum; + if (emojiSoundPlayer != null) { + emojiSoundPlayer.releasePlayer(true); + } + emojiSoundPlayer = new VideoPlayer(false); + emojiSoundPlayer.setDelegate(new VideoPlayer.VideoPlayerDelegate() { + @Override + public void onStateChanged(boolean playWhenReady, int playbackState) { + AndroidUtilities.runOnUIThread(() -> { + if (tag != emojiSoundPlayerNum) { + return; + } + if (playbackState == ExoPlayer.STATE_ENDED) { + if (emojiSoundPlayer != null) { + try { + emojiSoundPlayer.releasePlayer(true); + emojiSoundPlayer = null; + } catch (Exception e) { + FileLog.e(e); + } + } + } + }); + } + + @Override + public void onError(VideoPlayer player, Exception e) { + + } + + @Override + public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { + + } + + @Override + public void onRenderedFirstFrame() { + + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { + + } + + @Override + public boolean onSurfaceDestroyed(SurfaceTexture surfaceTexture) { + return false; + } + }); + emojiSoundPlayer.preparePlayer(Uri.fromFile(file), "other"); + emojiSoundPlayer.setStreamType(AudioManager.STREAM_MUSIC); + emojiSoundPlayer.play(); + } catch (Exception e) { + FileLog.e(e); + if (emojiSoundPlayer != null) { + emojiSoundPlayer.releasePlayer(true); + emojiSoundPlayer = null; + } + } + }); + } else { + AndroidUtilities.runOnUIThread(() -> accountInstance.getFileLoader().loadFile(document, null, 1, 1)); + } + }); + } + public boolean playMessage(final MessageObject messageObject) { if (messageObject == null) { return false; @@ -3372,7 +3461,226 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, }); } + private static class MediaLoader implements NotificationCenter.NotificationCenterDelegate { + + private AccountInstance currentAccount; + private AlertDialog progressDialog; + private ArrayList messageObjects; + private HashMap loadingMessageObjects = new HashMap<>(); + private float finishedProgress; + private boolean cancelled; + private boolean finished; + private int copiedFiles; + private CountDownLatch waitingForFile; + private MessagesStorage.IntCallback onFinishRunnable; + private boolean isMusic; + + public MediaLoader(Context context, AccountInstance accountInstance, ArrayList messages, MessagesStorage.IntCallback onFinish) { + currentAccount = accountInstance; + messageObjects = messages; + onFinishRunnable = onFinish; + isMusic = messages.get(0).isMusic(); + currentAccount.getNotificationCenter().addObserver(this, NotificationCenter.fileDidLoad); + currentAccount.getNotificationCenter().addObserver(this, NotificationCenter.FileLoadProgressChanged); + currentAccount.getNotificationCenter().addObserver(this, NotificationCenter.fileDidFailToLoad); + progressDialog = new AlertDialog(context, 2); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(true); + progressDialog.setOnCancelListener(d -> cancelled = true); + } + + public void start() { + AndroidUtilities.runOnUIThread(() -> { + if (!finished) { + progressDialog.show(); + } + }, 250); + + new Thread(() -> { + try { + File dir; + if (isMusic) { + dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); + } else { + dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + } + dir.mkdir(); + for (int b = 0, N = messageObjects.size(); b < N; b++) { + MessageObject message = messageObjects.get(b); + String name = message.getDocumentName(); + File destFile = new File(dir, name); + if (destFile.exists()) { + int idx = name.lastIndexOf('.'); + for (int a = 0; a < 10; a++) { + String newName; + if (idx != -1) { + newName = name.substring(0, idx) + "(" + (a + 1) + ")" + name.substring(idx); + } else { + newName = name + "(" + (a + 1) + ")"; + } + destFile = new File(dir, newName); + if (!destFile.exists()) { + break; + } + } + } + if (!destFile.exists()) { + destFile.createNewFile(); + } + String path = message.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(message.messageOwner).toString(); + } + File sourceFile = new File(path); + if (!sourceFile.exists()) { + waitingForFile = new CountDownLatch(1); + addMessageToLoad(message); + waitingForFile.await(); + } + copyFile(sourceFile, destFile, message.getMimeType()); + } + checkIfFinished(); + } catch (Exception e) { + FileLog.e(e); + } + + }).start(); + } + + private void checkIfFinished() { + if (!loadingMessageObjects.isEmpty()) { + return; + } + AndroidUtilities.runOnUIThread(() -> { + try { + if (progressDialog.isShowing()) { + progressDialog.dismiss(); + } else { + finished = true; + } + if (onFinishRunnable != null) { + AndroidUtilities.runOnUIThread(() -> onFinishRunnable.run(copiedFiles)); + } + } catch (Exception e) { + FileLog.e(e); + } + currentAccount.getNotificationCenter().removeObserver(this, NotificationCenter.fileDidLoad); + currentAccount.getNotificationCenter().removeObserver(this, NotificationCenter.FileLoadProgressChanged); + currentAccount.getNotificationCenter().removeObserver(this, NotificationCenter.fileDidFailToLoad); + }); + } + + private void addMessageToLoad(MessageObject messageObject) { + AndroidUtilities.runOnUIThread(() -> { + TLRPC.Document document = messageObject.getDocument(); + if (document == null) { + return; + } + String fileName = FileLoader.getAttachFileName(document); + loadingMessageObjects.put(fileName, messageObject); + currentAccount.getFileLoader().loadFile(document, messageObject, 1, 0); + }); + } + + private boolean copyFile(File sourceFile, File destFile, String mime) { + if (AndroidUtilities.isInternalUri(Uri.fromFile(sourceFile))) { + return false; + } + try (FileInputStream inputStream = new FileInputStream(sourceFile); FileChannel source = inputStream.getChannel(); FileChannel destination = new FileOutputStream(destFile).getChannel()) { + long size = source.size(); + try { + @SuppressLint("DiscouragedPrivateApi") Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$"); + int fdint = (Integer) getInt.invoke(inputStream.getFD()); + if (AndroidUtilities.isInternalUri(fdint)) { + if (progressDialog != null) { + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + return false; + } + } catch (Throwable e) { + FileLog.e(e); + } + long lastProgress = 0; + for (long a = 0; a < size; a += 4096) { + if (cancelled) { + break; + } + destination.transferFrom(source, a, Math.min(4096, size - a)); + } + if (!cancelled) { + if (isMusic) { + AndroidUtilities.addMediaToGallery(Uri.fromFile(destFile)); + } else { + DownloadManager downloadManager = (DownloadManager) ApplicationLoader.applicationContext.getSystemService(Context.DOWNLOAD_SERVICE); + downloadManager.addCompletedDownload(destFile.getName(), destFile.getName(), false, mime, destFile.getAbsolutePath(), destFile.length(), true); + } + finishedProgress += 100.0f / messageObjects.size(); + final int progress = (int) (finishedProgress); + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.setProgress(progress); + } catch (Exception e) { + FileLog.e(e); + } + }); + copiedFiles++; + return true; + } + } catch (Exception e) { + FileLog.e(e); + } + destFile.delete(); + return false; + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.fileDidLoad || id == NotificationCenter.fileDidFailToLoad) { + String fileName = (String) args[0]; + if (loadingMessageObjects.remove(fileName) != null) { + waitingForFile.countDown(); + } + } else if (id == NotificationCenter.FileLoadProgressChanged) { + String fileName = (String) args[0]; + if (loadingMessageObjects.containsKey(fileName)) { + Long loadedSize = (Long) args[1]; + Long totalSize = (Long) args[2]; + float loadProgress = loadedSize / (float) totalSize; + final int progress = (int) (finishedProgress + loadProgress / messageObjects.size() * 100); + AndroidUtilities.runOnUIThread(() -> { + try { + progressDialog.setProgress(progress); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + } + } + } + + public static void saveFilesFromMessages(Context context, AccountInstance accountInstance, ArrayList messageObjects, final MessagesStorage.IntCallback onSaved) { + new MediaLoader(context, accountInstance, messageObjects, onSaved).start(); + } + public static void saveFile(String fullPath, Context context, final int type, final String name, final String mime) { + saveFile(fullPath, context, type, name, mime, null); + } + + public static void saveFile(String fullPath, Context context, final int type, final String name, final String mime, final Runnable onSaved) { if (fullPath == null) { return; } @@ -3393,14 +3701,20 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, final boolean[] cancelled = new boolean[]{false}; if (sourceFile.exists()) { AlertDialog progressDialog = null; + final boolean[] finished = new boolean[1]; if (context != null && type != 0) { try { - progressDialog = new AlertDialog(context, 2); - progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(true); - progressDialog.setOnCancelListener(dialog -> cancelled[0] = true); - progressDialog.show(); + final AlertDialog dialog = new AlertDialog(context, 2); + dialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + dialog.setCanceledOnTouchOutside(false); + dialog.setCancelable(true); + dialog.setOnCancelListener(d -> cancelled[0] = true); + AndroidUtilities.runOnUIThread(() -> { + if (!finished[0]) { + dialog.show(); + } + }, 250); + progressDialog = dialog; } catch (Exception e) { FileLog.e(e); } @@ -3500,6 +3814,9 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, } else { AndroidUtilities.addMediaToGallery(Uri.fromFile(destFile)); } + if (onSaved != null) { + AndroidUtilities.runOnUIThread(onSaved); + } } } catch (Exception e) { FileLog.e(e); @@ -3507,7 +3824,11 @@ public class MediaController implements AudioManager.OnAudioFocusChangeListener, if (finalProgress != null) { AndroidUtilities.runOnUIThread(() -> { try { - finalProgress.dismiss(); + if (finalProgress.isShowing()) { + finalProgress.dismiss(); + } else { + finished[0] = true; + } } catch (Exception e) { FileLog.e(e); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java index 579bba63e..ed97f9736 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaDataController.java @@ -201,6 +201,7 @@ public class MediaDataController extends BaseController { stickersLoaded[a] = false; } featuredStickerSets.clear(); + loadingPinnedMessages.clear(); loadFeaturedDate = 0; loadFeaturedHash = 0; allStickers.clear(); @@ -1879,7 +1880,7 @@ public class MediaDataController extends BaseController { final StickerSetBulletinLayout bulletinLayout = new StickerSetBulletinLayout(context, stickerSetObject, toggle); final int finalCurrentIndex = currentIndex; Context finalContext = context; - final Bulletin.UndoButton undoButton = new Bulletin.UndoButton(context).setUndoAction(() -> { + final Bulletin.UndoButton undoButton = new Bulletin.UndoButton(context, false).setUndoAction(() -> { stickerSet.archived = false; stickerSets[type].add(finalCurrentIndex, messages_stickerSet); @@ -2007,6 +2008,7 @@ public class MediaDataController extends BaseController { private int lastReqId; private int lastGuid; private TLRPC.User lastSearchUser; + private TLRPC.Chat lastSearchChat; private int[] messagesSearchCount = new int[]{0, 0}; private boolean[] messagesSearchEndReached = new boolean[]{false, false}; private ArrayList searchResultMessages = new ArrayList<>(); @@ -2038,8 +2040,8 @@ public class MediaDataController extends BaseController { return searchResultMessagesMap[mergeDialog ? 1 : 0].indexOfKey(messageId) >= 0; } - public void searchMessagesInChat(String query, final long dialogId, final long mergeDialogId, final int guid, final int direction, int replyMessageId, TLRPC.User user) { - searchMessagesInChat(query, dialogId, mergeDialogId, guid, direction, replyMessageId, false, user, true); + public void searchMessagesInChat(String query, final long dialogId, final long mergeDialogId, final int guid, final int direction, int replyMessageId, TLRPC.User user, TLRPC.Chat chat) { + searchMessagesInChat(query, dialogId, mergeDialogId, guid, direction, replyMessageId, false, user, chat, true); } public void jumpToSearchedMessage(int guid, int index) { @@ -2057,12 +2059,12 @@ public class MediaDataController extends BaseController { } int temp = searchResultMessages.size(); lastReturnedNum = searchResultMessages.size(); - searchMessagesInChat(null, lastDialogId, lastMergeDialogId, lastGuid, 1, lastReplyMessageId, false, lastSearchUser, false); + searchMessagesInChat(null, lastDialogId, lastMergeDialogId, lastGuid, 1, lastReplyMessageId, false, lastSearchUser, lastSearchChat, false); lastReturnedNum = temp; loadingMoreSearchMessages = true; } - private void searchMessagesInChat(String query, final long dialogId, final long mergeDialogId, final int guid, final int direction, int replyMessageId, final boolean internal, final TLRPC.User user, boolean jumpToMessage) { + private void searchMessagesInChat(String query, final long dialogId, final long mergeDialogId, final int guid, final int direction, int replyMessageId, final boolean internal, final TLRPC.User user, final TLRPC.Chat chat, boolean jumpToMessage) { int max_id = 0; long queryWithDialog = dialogId; boolean firstQuery = !internal; @@ -2139,9 +2141,12 @@ public class MediaDataController extends BaseController { req.peer = inputPeer; lastMergeDialogId = mergeDialogId; req.limit = 1; - req.q = query != null ? query : ""; + req.q = query; if (user != null) { - req.from_id = getMessagesController().getInputUser(user); + req.from_id = MessagesController.getInputPeer(user); + req.flags |= 1; + } else if (chat != null) { + req.from_id = MessagesController.getInputPeer(chat); req.flags |= 1; } req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); @@ -2152,7 +2157,7 @@ public class MediaDataController extends BaseController { TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; messagesSearchEndReached[1] = res.messages.isEmpty(); messagesSearchCount[1] = res instanceof TLRPC.TL_messages_messagesSlice ? res.count : res.messages.size(); - searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, jumpToMessage); + searchMessagesInChat(req.q, dialogId, mergeDialogId, guid, direction, replyMessageId, true, user, chat, jumpToMessage); } } }), ConnectionsManager.RequestFlagFailOnServerErrors); @@ -2171,12 +2176,16 @@ public class MediaDataController extends BaseController { lastGuid = guid; lastDialogId = dialogId; lastSearchUser = user; + lastSearchChat = chat; lastReplyMessageId = replyMessageId; req.limit = 21; req.q = query != null ? query : ""; req.offset_id = max_id; if (user != null) { - req.from_id = getMessagesController().getInputUser(user); + req.from_id = MessagesController.getInputPeer(user); + req.flags |= 1; + } else if (chat != null) { + req.from_id = MessagesController.getInputPeer(chat); req.flags |= 1; } if (lastReplyMessageId != 0) { @@ -2250,7 +2259,7 @@ public class MediaDataController extends BaseController { } } if (queryWithDialogFinal == dialogId && messagesSearchEndReached[0] && mergeDialogId != 0 && !messagesSearchEndReached[1]) { - searchMessagesInChat(lastSearchQuery, dialogId, mergeDialogId, guid, 0, replyMessageId, true, user, jumpToMessage); + searchMessagesInChat(lastSearchQuery, dialogId, mergeDialogId, guid, 0, replyMessageId, true, user, chat, jumpToMessage); } } } @@ -3637,35 +3646,102 @@ public class MediaDataController extends BaseController { return 0; }; - public MessageObject loadPinnedMessage(final long dialogId, final int channelId, final int mid, boolean useQueue) { + private LongSparseArray loadingPinnedMessages = new LongSparseArray<>(); + + public void loadPinnedMessages(long dialogId, int maxId, int fallback) { + if (loadingPinnedMessages.indexOfKey(dialogId) >= 0) { + return; + } + loadingPinnedMessages.put(dialogId, true); + TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); + req.peer = getMessagesController().getInputPeer((int) dialogId); + req.limit = 40; + req.offset_id = maxId; + req.q = ""; + req.filter = new TLRPC.TL_inputMessagesFilterPinned(); + getConnectionsManager().sendRequest(req, (response, error) -> { + ArrayList ids = new ArrayList<>(); + HashMap messages = new HashMap<>(); + int totalCount = 0; + boolean endReached; + if (response instanceof TLRPC.messages_Messages) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + final SparseArray usersDict = new SparseArray<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + final SparseArray chatsDict = new SparseArray<>(); + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + chatsDict.put(chat.id, chat); + } + getMessagesStorage().putUsersAndChats(res.users, res.chats, true, true); + getMessagesController().putUsers(res.users, false); + getMessagesController().putChats(res.chats, false); + for (int a = 0, N = res.messages.size(); a < N; a++) { + TLRPC.Message message = res.messages.get(a); + if (message instanceof TLRPC.TL_messageService || message instanceof TLRPC.TL_messageEmpty) { + continue; + } + ids.add(message.id); + messages.put(message.id, new MessageObject(currentAccount, message, usersDict, chatsDict, false, false)); + } + if (fallback != 0 && ids.isEmpty()) { + ids.add(fallback); + } + endReached = res.messages.size() < req.limit; + totalCount = Math.max(res.count, res.messages.size()); + } else { + if (fallback != 0) { + ids.add(fallback); + totalCount = 1; + } + endReached = false; + } + getMessagesStorage().updatePinnedMessages(dialogId, ids, true, totalCount, maxId, endReached, messages); + AndroidUtilities.runOnUIThread(() -> loadingPinnedMessages.remove(dialogId)); + }); + } + + public ArrayList loadPinnedMessages(long dialogId, int channelId, ArrayList mids, boolean useQueue) { if (useQueue) { - getMessagesStorage().getStorageQueue().postRunnable(() -> loadPinnedMessageInternal(dialogId, channelId, mid, false)); + getMessagesStorage().getStorageQueue().postRunnable(() -> loadPinnedMessageInternal(dialogId, channelId, mids, false)); } else { - return loadPinnedMessageInternal(dialogId, channelId, mid, true); + return loadPinnedMessageInternal(dialogId, channelId, mids, true); } return null; } - private MessageObject loadPinnedMessageInternal(final long dialogId, final int channelId, final int mid, boolean returnValue) { + private ArrayList loadPinnedMessageInternal(long dialogId, int channelId, ArrayList mids, boolean returnValue) { try { - long messageId; + ArrayList midsCopy = new ArrayList<>(mids); + CharSequence longIds; if (channelId != 0) { - messageId = ((long) mid) | ((long) channelId) << 32; + StringBuilder builder = new StringBuilder(); + for (int a = 0, N = mids.size(); a < N; a++) { + long messageId = ((long) mids.get(a)) | ((long) channelId) << 32; + if (builder.length() != 0) { + builder.append(","); + } + builder.append(messageId); + } + longIds = builder; } else { - messageId = mid; + longIds = TextUtils.join(",", mids); } - TLRPC.Message result = null; + ArrayList results = new ArrayList<>(); final ArrayList users = new ArrayList<>(); final ArrayList chats = new ArrayList<>(); ArrayList usersToLoad = new ArrayList<>(); ArrayList chatsToLoad = new ArrayList<>(); - SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid = %d", messageId)); - if (cursor.next()) { + SQLiteCursor cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN (%s)", longIds)); + while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { - result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + TLRPC.Message result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); result.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); if (result.action instanceof TLRPC.TL_messageActionHistoryClear) { @@ -3675,55 +3751,66 @@ public class MediaDataController extends BaseController { result.date = cursor.intValue(2); result.dialog_id = dialogId; MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad); + results.add(result); } + midsCopy.remove((Integer) result.id); } } cursor.dispose(); - if (result == null) { - cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data FROM chat_pinned WHERE uid = %d", dialogId)); - if (cursor.next()) { + if (!midsCopy.isEmpty()) { + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data FROM chat_pinned_v2 WHERE uid = %d AND mid IN (%s)", dialogId, TextUtils.join(",", midsCopy))); + while (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { - result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + TLRPC.Message result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); result.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); - if (result.id != mid || result.action instanceof TLRPC.TL_messageActionHistoryClear) { + if (result.action instanceof TLRPC.TL_messageActionHistoryClear) { result = null; } else { result.dialog_id = dialogId; MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad); + results.add(result); } + midsCopy.remove((Integer) result.id); } } cursor.dispose(); } - if (result == null) { + if (!midsCopy.isEmpty()) { if (channelId != 0) { final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); req.channel = getMessagesController().getInputChannel(channelId); - req.id.add(mid); + req.id = midsCopy; getConnectionsManager().sendRequest(req, (response, error) -> { boolean ok = false; if (error == null) { TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; removeEmptyMessages(messagesRes.messages); if (!messagesRes.messages.isEmpty()) { + TLRPC.Chat chat = getMessagesController().getChat(channelId); + if (chat != null && chat.megagroup) { + for (int a = 0, N = messagesRes.messages.size(); a < N; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } ImageLoader.saveMessagesThumbs(messagesRes.messages); - broadcastPinnedMessage(messagesRes.messages.get(0), messagesRes.users, messagesRes.chats, false, false); + broadcastPinnedMessage(messagesRes.messages, messagesRes.users, messagesRes.chats, false, false); getMessagesStorage().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); - savePinnedMessage(messagesRes.messages.get(0)); + savePinnedMessages(dialogId, messagesRes.messages); ok = true; } } if (!ok) { - getMessagesStorage().updateChatPinnedMessage(channelId, 0); + getMessagesStorage().updatePinnedMessages(dialogId, req.id, false, -1, 0, false, null); } }); } else { final TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); - req.id.add(mid); + req.id = midsCopy; getConnectionsManager().sendRequest(req, (response, error) -> { boolean ok = false; if (error == null) { @@ -3731,20 +3818,21 @@ public class MediaDataController extends BaseController { removeEmptyMessages(messagesRes.messages); if (!messagesRes.messages.isEmpty()) { ImageLoader.saveMessagesThumbs(messagesRes.messages); - broadcastPinnedMessage(messagesRes.messages.get(0), messagesRes.users, messagesRes.chats, false, false); + broadcastPinnedMessage(messagesRes.messages, messagesRes.users, messagesRes.chats, false, false); getMessagesStorage().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); - savePinnedMessage(messagesRes.messages.get(0)); + savePinnedMessages(dialogId, messagesRes.messages); ok = true; } } if (!ok) { - getMessagesStorage().updateChatPinnedMessage(channelId, 0); + getMessagesStorage().updatePinnedMessages(dialogId, req.id, false, -1, 0, false, null); } }); } - } else { + } + if (!results.isEmpty()) { if (returnValue) { - return broadcastPinnedMessage(result, users, chats, true, returnValue); + return broadcastPinnedMessage(results, users, chats, true, true); } else { if (!usersToLoad.isEmpty()) { getMessagesStorage().getUsersInternal(TextUtils.join(",", usersToLoad), users); @@ -3752,7 +3840,7 @@ public class MediaDataController extends BaseController { if (!chatsToLoad.isEmpty()) { getMessagesStorage().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); } - broadcastPinnedMessage(result, users, chats, true, false); + broadcastPinnedMessage(results, users, chats, true, false); } } } catch (Exception e) { @@ -3761,29 +3849,26 @@ public class MediaDataController extends BaseController { return null; } - private void savePinnedMessage(final TLRPC.Message result) { + private void savePinnedMessages(long dialogId, ArrayList arrayList) { + if (arrayList.isEmpty()) { + return; + } getMessagesStorage().getStorageQueue().postRunnable(() -> { try { - long dialogId; - if (result.peer_id.channel_id != 0) { - dialogId = -result.peer_id.channel_id; - } else if (result.peer_id.chat_id != 0) { - dialogId = -result.peer_id.chat_id; - } else if (result.peer_id.user_id != 0) { - dialogId = result.peer_id.user_id; - } else { - return; - } getMessagesStorage().getDatabase().beginTransaction(); - SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO chat_pinned VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize()); - result.serializeToStream(data); - state.requery(); - state.bindLong(1, dialogId); - state.bindInteger(2, result.id); - state.bindByteBuffer(3, data); - state.step(); - data.reuse(); + //SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("UPDATE chat_pinned_v2 SET data = ? WHERE uid = ? AND mid = ?"); + SQLitePreparedStatement state = getMessagesStorage().getDatabase().executeFast("REPLACE INTO chat_pinned_v2 VALUES(?, ?, ?)"); + for (int a = 0, N = arrayList.size(); a < N; a++) { + TLRPC.Message message = arrayList.get(a); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state.requery(); + state.bindLong(1, dialogId); + state.bindInteger(2, message.id); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + } state.dispose(); getMessagesStorage().getDatabase().commitTransaction(); } catch (Exception e) { @@ -3792,7 +3877,10 @@ public class MediaDataController extends BaseController { }); } - private MessageObject broadcastPinnedMessage(final TLRPC.Message result, final ArrayList users, final ArrayList chats, final boolean isCache, boolean returnValue) { + private ArrayList broadcastPinnedMessage(final ArrayList results, final ArrayList users, final ArrayList chats, final boolean isCache, boolean returnValue) { + if (results.isEmpty()) { + return null; + } final SparseArray usersDict = new SparseArray<>(); for (int a = 0; a < users.size(); a++) { TLRPC.User user = users.get(a); @@ -3803,13 +3891,24 @@ public class MediaDataController extends BaseController { TLRPC.Chat chat = chats.get(a); chatsDict.put(chat.id, chat); } + ArrayList messageObjects = new ArrayList<>(); if (returnValue) { - return new MessageObject(currentAccount, result, usersDict, chatsDict, false, false); + AndroidUtilities.runOnUIThread(() -> { + getMessagesController().putUsers(users, isCache); + getMessagesController().putChats(chats, isCache); + }); + for (int a = 0, N = results.size(); a < N; a++) { + messageObjects.add(new MessageObject(currentAccount, results.get(a), usersDict, chatsDict, false, false)); + } + return messageObjects; } else { AndroidUtilities.runOnUIThread(() -> { getMessagesController().putUsers(users, isCache); getMessagesController().putChats(chats, isCache); - getNotificationCenter().postNotificationName(NotificationCenter.pinnedMessageDidLoad, new MessageObject(currentAccount, result, usersDict, chatsDict, false, false)); + for (int a = 0, N = results.size(); a < N; a++) { + messageObjects.add(new MessageObject(currentAccount, results.get(a), usersDict, chatsDict, false, false)); + } + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, messageObjects.get(0).getDialogId(), null, true, messageObjects, null, 0, -1, false)); }); } return null; @@ -3831,6 +3930,9 @@ public class MediaDataController extends BaseController { final LongSparseArray> replyMessageRandomOwners = new LongSparseArray<>(); for (int a = 0; a < messages.size(); a++) { MessageObject messageObject = messages.get(a); + if (messageObject == null) { + continue; + } if (messageObject.isReply() && messageObject.replyMessageObject == null) { long id = messageObject.messageOwner.reply_to.reply_to_random_id; ArrayList messageObjects = replyMessageRandomOwners.get(id); @@ -3907,6 +4009,9 @@ public class MediaDataController extends BaseController { final StringBuilder stringBuilder = new StringBuilder(); for (int a = 0; a < messages.size(); a++) { MessageObject messageObject = messages.get(a); + if (messageObject == null) { + continue; + } if (messageObject.getId() > 0 && messageObject.isReply() && messageObject.replyMessageObject == null) { int id = messageObject.messageOwner.reply_to.reply_to_msg_id; long messageId = id; @@ -4775,8 +4880,8 @@ public class MediaDataController extends BaseController { FileLog.e(e); } } + SparseArray threads = draftMessages.get(did); if (replyToMessage == null) { - SparseArray threads = draftMessages.get(did); if (threads != null) { threads.remove(threadId); if (threads.size() == 0) { @@ -4789,7 +4894,6 @@ public class MediaDataController extends BaseController { editor.remove("rt_" + did + "_" + threadId); } } else { - SparseArray threads = draftMessages.get(did); if (threads == null) { threads = new SparseArray<>(); draftMessages.put(did, threads); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java index 49b416ce1..6c33213f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -123,6 +123,8 @@ public class MessageObject { public boolean isRestrictedMessage; public long loadedFileSize; + public boolean animateComments; + public boolean loadingCancelled; public int stableId; @@ -171,6 +173,7 @@ public class MessageObject { public CharSequence vCardData; public ArrayList highlightedWords; + public String messageTrimmedToHighlight; static final String[] excludeWords = new String[]{ " vs. ", @@ -259,10 +262,7 @@ public class MessageObject { if (nameEncoding != null && nameEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) { byte[] bytes = AndroidUtilities.decodeQuotedPrintable(AndroidUtilities.getStringBytes(currentData.company)); if (bytes != null && bytes.length != 0) { - String decodedName = new String(bytes, nameCharset); - if (decodedName != null) { - currentData.company = decodedName; - } + currentData.company = new String(bytes, nameCharset); } } currentData.company = currentData.company.replace(';', ' '); @@ -369,6 +369,7 @@ public class MessageObject { public ArrayList messages = new ArrayList<>(); public ArrayList posArray = new ArrayList<>(); public HashMap positions = new HashMap<>(); + public boolean isDocuments; private int maxSizeWidth = 800; @@ -422,6 +423,7 @@ public class MessageObject { int maxX = 0; boolean forceCalc = false; boolean needShare = false; + boolean isMusic = false; hasSibling = false; hasCaption = false; @@ -435,6 +437,9 @@ public class MessageObject { messageObject.messageOwner.from_id instanceof TLRPC.TL_peerUser && (messageObject.messageOwner.peer_id.channel_id != 0 || messageObject.messageOwner.peer_id.chat_id != 0 || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice) ); + if (messageObject.isMusic() || messageObject.isDocument()) { + isDocuments = true; + } } TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); GroupedMessagePosition position = new GroupedMessagePosition(); @@ -462,6 +467,28 @@ public class MessageObject { hasCaption = true; } } + if (isDocuments) { + for (int a = 0; a < count; a++) { + GroupedMessagePosition pos = posArray.get(a); + pos.flags |= POSITION_FLAG_LEFT | POSITION_FLAG_RIGHT; + if (a == 0) { + pos.flags |= POSITION_FLAG_TOP; + } else if (a == count - 1) { + pos.flags |= POSITION_FLAG_BOTTOM; + pos.last = true; + } + pos.edge = true; + pos.aspectRatio = 1.0f; + pos.minX = 0; + pos.maxX = 0; + pos.minY = (byte) a; + pos.maxY = (byte) a; + pos.spanSize = 1000; + pos.pw = maxSizeWidth; + pos.ph = 100; + } + return; + } if (needShare) { maxSizeWidth -= 50; @@ -546,7 +573,7 @@ public class MessageObject { position3.set(1, 1, 1, 1, width, secondHeight, POSITION_FLAG_RIGHT | POSITION_FLAG_BOTTOM); maxX = 1; } - } else if (count == 4) { + } else { GroupedMessagePosition position1 = posArray.get(0); GroupedMessagePosition position2 = posArray.get(1); GroupedMessagePosition position3 = posArray.get(2); @@ -1001,9 +1028,7 @@ public class MessageObject { TLRPC.User fromUser = null; if (event.user_id > 0) { - if (fromUser == null) { - fromUser = MessagesController.getInstance(currentAccount).getUser(event.user_id); - } + fromUser = MessagesController.getInstance(currentAccount).getUser(event.user_id); } Calendar rightNow = new GregorianCalendar(); @@ -1172,10 +1197,8 @@ public class MessageObject { n = new TLRPC.TL_chatBannedRights(); } if (o.send_messages != n.send_messages) { - if (!added) { - rights.append('\n'); - added = true; - } + rights.append('\n'); + added = true; rights.append('\n').append(!n.send_messages ? '+' : '-').append(' '); rights.append(LocaleController.getString("EventLogRestrictedSendMessages", R.string.EventLogRestrictedSendMessages)); } @@ -1241,7 +1264,7 @@ public class MessageObject { TLRPC.User whoUser = MessagesController.getInstance(currentAccount).getUser(event.action.prev_participant.user_id); TLRPC.TL_chatBannedRights o = event.action.prev_participant.banned_rights; TLRPC.TL_chatBannedRights n = event.action.new_participant.banned_rights; - if (chat.megagroup && (n == null || !n.view_messages || n != null && o != null && n.until_date != o.until_date)) { + if (chat.megagroup && (n == null || !n.view_messages || o != null && n.until_date != o.until_date)) { StringBuilder rights; StringBuilder bannedDuration; if (n != null && !AndroidUtilities.isBannedForever(n)) { @@ -1295,10 +1318,8 @@ public class MessageObject { n = new TLRPC.TL_chatBannedRights(); } if (o.view_messages != n.view_messages) { - if (!added) { - rights.append('\n'); - added = true; - } + rights.append('\n'); + added = true; rights.append('\n').append(!n.view_messages ? '+' : '-').append(' '); rights.append(LocaleController.getString("EventLogRestrictedReadMessages", R.string.EventLogRestrictedReadMessages)); } @@ -1383,13 +1404,13 @@ public class MessageObject { } else if (event.action instanceof TLRPC.TL_channelAdminLogEventActionUpdatePinned) { if (fromUser != null && fromUser.id == 136817688 && event.action.message.fwd_from != null && event.action.message.fwd_from.from_id instanceof TLRPC.TL_peerChannel) { TLRPC.Chat channel = MessagesController.getInstance(currentAccount).getChat(event.action.message.fwd_from.from_id.channel_id); - if (event.action.message instanceof TLRPC.TL_messageEmpty) { + if (event.action.message instanceof TLRPC.TL_messageEmpty || !event.action.message.pinned) { messageText = replaceWithLink(LocaleController.getString("EventLogUnpinnedMessages", R.string.EventLogUnpinnedMessages), "un1", channel); } else { messageText = replaceWithLink(LocaleController.getString("EventLogPinnedMessages", R.string.EventLogPinnedMessages), "un1", channel); } } else { - if (event.action.message instanceof TLRPC.TL_messageEmpty) { + if (event.action.message instanceof TLRPC.TL_messageEmpty || !event.action.message.pinned) { messageText = replaceWithLink(LocaleController.getString("EventLogUnpinnedMessages", R.string.EventLogUnpinnedMessages), "un1", fromUser); } else { messageText = replaceWithLink(LocaleController.getString("EventLogPinnedMessages", R.string.EventLogPinnedMessages), "un1", fromUser); @@ -2122,6 +2143,9 @@ public class MessageObject { } public void measureInlineBotButtons() { + if (isRestrictedMessage) { + return; + } wantedBotKeyboardWidth = 0; if (messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup || messageOwner.reactions != null && !messageOwner.reactions.results.isEmpty()) { Theme.createChatResources(null, true); @@ -2187,33 +2211,72 @@ public class MessageObject { return localType != 0; } + private TLRPC.User getUser(AbstractMap users, SparseArray sUsers, int uid) { + TLRPC.User user = null; + if (users != null) { + user = users.get(uid); + } else if (sUsers != null) { + user = sUsers.get(uid); + } + if (user == null) { + user = MessagesController.getInstance(currentAccount).getUser(uid); + } + return user; + } + + private TLRPC.Chat getChat(AbstractMap chats, SparseArray sChats, int cid) { + TLRPC.Chat chat = null; + if (chats != null) { + chat = chats.get(cid); + } else if (sChats != null) { + chat = sChats.get(cid); + } + if (chat == null) { + chat = MessagesController.getInstance(currentAccount).getChat(cid); + } + return chat; + } + private void updateMessageText(AbstractMap users, AbstractMap chats, SparseArray sUsers, SparseArray sChats) { TLRPC.User fromUser = null; TLRPC.Chat fromChat = null; if (messageOwner.from_id instanceof TLRPC.TL_peerUser) { - if (users != null) { - fromUser = users.get(messageOwner.from_id.user_id); - } else if (sUsers != null) { - fromUser = sUsers.get(messageOwner.from_id.user_id); - } - if (fromUser == null) { - fromUser = MessagesController.getInstance(currentAccount).getUser(messageOwner.from_id.user_id); - } + fromUser = getUser(users, sUsers, messageOwner.from_id.user_id); } else if (messageOwner.from_id instanceof TLRPC.TL_peerChannel) { - if (chats != null) { - fromChat = chats.get(messageOwner.from_id.channel_id); - } else if (sChats != null) { - fromChat = sChats.get(messageOwner.from_id.channel_id); - } - if (fromChat == null) { - fromChat = MessagesController.getInstance(currentAccount).getChat(messageOwner.from_id.channel_id); - } + fromChat = getChat(chats, sChats, messageOwner.from_id.channel_id); } TLObject fromObject = fromUser != null ? fromUser : fromChat; if (messageOwner instanceof TLRPC.TL_messageService) { if (messageOwner.action != null) { - if (messageOwner.action instanceof TLRPC.TL_messageActionCustomAction) { + if (messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) { + TLRPC.TL_messageActionGeoProximityReached action = (TLRPC.TL_messageActionGeoProximityReached) messageOwner.action; + int fromId = getPeerId(action.from_id); + TLObject from; + if (fromId > 0) { + from = getUser(users, sUsers, fromId); + } else { + from = getChat(chats, sChats, -fromId); + } + int toId = getPeerId(action.to_id); + int selfUserId = UserConfig.getInstance(currentAccount).getClientUserId(); + if (toId == selfUserId) { + messageText = replaceWithLink(LocaleController.formatString("ActionUserWithinRadius", R.string.ActionUserWithinRadius, LocaleController.formatDistance(action.distance, 2)), "un1", from); + } else { + TLObject to; + if (toId > 0) { + to = getUser(users, sUsers, toId); + } else { + to = getChat(chats, sChats, -toId); + } + if (fromId == selfUserId) { + messageText = replaceWithLink(LocaleController.formatString("ActionUserWithinYouRadius", R.string.ActionUserWithinYouRadius, LocaleController.formatDistance(action.distance, 2)), "un1", to); + } else { + messageText = replaceWithLink(LocaleController.formatString("ActionUserWithinOtherRadius", R.string.ActionUserWithinOtherRadius, LocaleController.formatDistance(action.distance, 2)), "un2", to); + messageText = replaceWithLink(messageText, "un1", from); + } + } + } else if (messageOwner.action instanceof TLRPC.TL_messageActionCustomAction) { messageText = messageOwner.action.message; } else if (messageOwner.action instanceof TLRPC.TL_messageActionChatCreate) { if (isOut()) { @@ -2637,7 +2700,7 @@ public class MessageObject { messageText = LocaleController.getString("AttachGif", R.string.AttachGif); } else { String name = FileLoader.getDocumentFileName(getDocument()); - if (name != null && name.length() > 0) { + if (!TextUtils.isEmpty(name)) { messageText = name; } else { messageText = LocaleController.getString("AttachDocument", R.string.AttachDocument); @@ -2710,7 +2773,7 @@ public class MessageObject { } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { TLRPC.Document document = getDocument(); if (document != null && document.mime_type != null) { - if (isGifDocument(document)) { + if (isGifDocument(document, hasValidGroupId())) { type = 8; } else if (isSticker()) { type = TYPE_STICKER; @@ -2820,7 +2883,11 @@ public class MessageObject { } public static boolean isGifDocument(TLRPC.Document document) { - return document != null /*&& !document.thumbs.isEmpty()*/ && document.mime_type != null && (document.mime_type.equals("image/gif") || isNewGifDocument(document)); + return isGifDocument(document, false); + } + + public static boolean isGifDocument(TLRPC.Document document, boolean hasGroup) { + return document != null && document.mime_type != null && (document.mime_type.equals("image/gif") && !hasGroup || isNewGifDocument(document)); } public static boolean isDocumentHasThumb(TLRPC.Document document) { @@ -2868,7 +2935,7 @@ public class MessageObject { TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeVideo) { width = attribute.w; - height = attribute.w; + height = attribute.h; round = attribute.round_message; } } @@ -2959,7 +3026,7 @@ public class MessageObject { if (!update || photoThumbs == null) { photoThumbs = new ArrayList<>(); photoThumbs.addAll(emojiAnimatedSticker.thumbs); - } else if (photoThumbs != null && !photoThumbs.isEmpty()) { + } else if (!photoThumbs.isEmpty()) { updatePhotoSizeLocations(photoThumbs, emojiAnimatedSticker.thumbs); } photoThumbsObject = emojiAnimatedSticker; @@ -2994,7 +3061,7 @@ public class MessageObject { if (!update || photoThumbs == null) { photoThumbs = new ArrayList<>(); photoThumbs.addAll(document.thumbs); - } else if (photoThumbs != null && !photoThumbs.isEmpty()) { + } else if (!photoThumbs.isEmpty()) { updatePhotoSizeLocations(photoThumbs, document.thumbs); } photoThumbsObject = document; @@ -3407,13 +3474,13 @@ public class MessageObject { if (patternType == 1) { if (ch == '@') { url = new URLSpanNoUnderline("https://instagram.com/" + charSequence.subSequence(start + 1, end).toString()); - } else if (ch == '#') { + } else { url = new URLSpanNoUnderline("https://www.instagram.com/explore/tags/" + charSequence.subSequence(start + 1, end).toString()); } } else if (patternType == 2) { if (ch == '@') { url = new URLSpanNoUnderline("https://twitter.com/" + charSequence.subSequence(start + 1, end).toString()); - } else if (ch == '#') { + } else { url = new URLSpanNoUnderline("https://twitter.com/hashtag/" + charSequence.subSequence(start + 1, end).toString()); } } else { @@ -3491,7 +3558,7 @@ public class MessageObject { } public boolean hasValidGroupId() { - return getGroupId() != 0 && photoThumbs != null && !photoThumbs.isEmpty(); + return getGroupId() != 0 && (photoThumbs != null && !photoThumbs.isEmpty() || isMusic() || isDocument()); } public long getGroupIdForUse() { @@ -3507,16 +3574,20 @@ public class MessageObject { } public static void addLinks(boolean isOut, CharSequence messageText, boolean botCommands, boolean check) { + addLinks(isOut, messageText, botCommands, check, false); + } + + public static void addLinks(boolean isOut, CharSequence messageText, boolean botCommands, boolean check, boolean internalOnly) { if (messageText instanceof Spannable && containsUrls(messageText)) { if (messageText.length() < 1000) { try { - AndroidUtilities.addLinks((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS); + AndroidUtilities.addLinks((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS, internalOnly); } catch (Exception e) { FileLog.e(e); } } else { try { - AndroidUtilities.addLinks((Spannable) messageText, Linkify.WEB_URLS); + AndroidUtilities.addLinks((Spannable) messageText, Linkify.WEB_URLS, internalOnly); } catch (Exception e) { FileLog.e(e); } @@ -3674,7 +3745,7 @@ public class MessageObject { b++; N2++; runs.add(b, r); - } else if (newRun.end >= run.end) { + } else { TextStyleSpan.TextStyleRun r = new TextStyleSpan.TextStyleRun(newRun); r.merge(run); r.end = run.end; @@ -4654,7 +4725,7 @@ public class MessageObject { if (message.media instanceof TLRPC.TL_messageMediaWebPage) { return isGifDocument(message.media.webpage.document); } - return message.media != null && isGifDocument(message.media.document); + return message.media != null && isGifDocument(message.media.document, message.grouped_id != 0); } public static boolean isRoundVideoMessage(TLRPC.Message message) { @@ -4949,6 +5020,10 @@ public class MessageObject { return isMusicMessage(messageOwner); } + public boolean isDocument() { + return getDocument() != null && !isVideo() && !isMusic() && !isVoice() && !isAnyKindOfSticker(); + } + public boolean isVoice() { return isVoiceMessage(messageOwner); } @@ -4965,6 +5040,10 @@ public class MessageObject { return isLiveLocationMessage(messageOwner); } + public boolean isExpiredLiveLocation(int date) { + return messageOwner.date + messageOwner.media.period <= date; + } + public boolean isGame() { return isGameMessage(messageOwner); } @@ -5544,9 +5623,7 @@ public class MessageObject { if (currentPhotoObject == null) { return; } - if (currentPhotoObject != null) { - mediaExists = FileLoader.getPathToAttach(currentPhotoObject, true).exists(); - } + mediaExists = FileLoader.getPathToAttach(currentPhotoObject, true).exists(); } else if (type == 11) { TLRPC.Photo photo = messageOwner.action.photo; if (photo == null || photo.video_sizes.isEmpty()) { @@ -5576,15 +5653,12 @@ public class MessageObject { searchForWords.addAll(Arrays.asList(words)); } if (getDocument() != null) { - String fileName = FileLoader.getDocumentFileName(getDocument()); - if (fileName != null) { - fileName = fileName.toLowerCase(); - if (fileName.contains(query) && !foundWords.contains(query)) { - foundWords.add(query); - } - String[] words = fileName.split("\\P{L}+"); - searchForWords.addAll(Arrays.asList(words)); + String fileName = FileLoader.getDocumentFileName(getDocument()).toLowerCase(); + if (fileName.contains(query) && !foundWords.contains(query)) { + foundWords.add(query); } + String[] words = fileName.split("\\P{L}+"); + searchForWords.addAll(Arrays.asList(words)); } if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage instanceof TLRPC.TL_webPage) { @@ -5646,7 +5720,22 @@ public class MessageObject { } if (!foundWords.isEmpty()) { highlightedWords = foundWords; + if (messageOwner.message != null) { + String str = messageOwner.message.replace('\n', ' ').replaceAll(" +", " ").trim(); + int lastIndex = str.length(); + int startHighlightedIndex = str.toLowerCase().indexOf(foundWords.get(0)); + int maxSymbols = 130; + if (startHighlightedIndex < 0) { + startHighlightedIndex = 0; + } + if (lastIndex > maxSymbols) { + int newStart = Math.max(0, startHighlightedIndex - maxSymbols / 2); + str = str.substring(newStart, Math.min(lastIndex, startHighlightedIndex - newStart + startHighlightedIndex + maxSymbols / 2)); + } + messageTrimmedToHighlight = str; + } } + } public boolean hasHighlightedWords() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index ea960ab81..2464b2800 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -46,6 +46,7 @@ import org.telegram.ui.ProfileActivity; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -301,6 +302,7 @@ public class MessagesController extends BaseController implements NotificationCe public ArrayList gifSearchEmojies = new ArrayList<>(); public HashSet diceEmojies; public HashMap diceSuccess = new HashMap<>(); + public HashMap emojiSounds = new HashMap<>(); private SharedPreferences notificationsPreferences; private SharedPreferences mainPreferences; @@ -347,6 +349,33 @@ public class MessagesController extends BaseController implements NotificationCe } } + public static class EmojiSound { + public long id; + public long accessHash; + public byte[] fileReference; + + public EmojiSound(long i, long ah, String fr) { + id = i; + accessHash = ah; + fileReference = Base64.decode(fr, Base64.URL_SAFE); + } + + public EmojiSound(long i, long ah, byte[] fr) { + id = i; + accessHash = ah; + fileReference = fr; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof EmojiSound)) { + return false; + } + EmojiSound emojiSound = (EmojiSound) obj; + return id == emojiSound.id && accessHash == emojiSound.accessHash && Arrays.equals(fileReference, emojiSound.fileReference); + } + } + public static class DiceFrameSuccess { public int frame; public int num; @@ -540,7 +569,7 @@ public class MessagesController extends BaseController implements NotificationCe return 1; } else if (dialog1.pinned && !dialog2.pinned) { return -1; - } else if (dialog1.pinned && dialog2.pinned) { + } else if (dialog1.pinned) { if (dialog1.pinnedNum < dialog2.pinnedNum) { return 1; } else if (dialog1.pinnedNum > dialog2.pinnedNum) { @@ -806,6 +835,23 @@ public class MessagesController extends BaseController implements NotificationCe } } + text = mainPreferences.getString("emojiSounds", null); + if (text != null) { + try { + byte[] bytes = Base64.decode(text, Base64.DEFAULT); + if (bytes != null) { + SerializedData data = new SerializedData(bytes); + int count = data.readInt32(true); + for (int a = 0; a < count; a++) { + emojiSounds.put(data.readString(true), new EmojiSound(data.readInt64(true), data.readInt64(true), data.readByteArray(true))); + } + data.cleanup(); + } + } catch (Exception e) { + FileLog.e(e); + } + } + text = mainPreferences.getString("gifSearchEmojies", null); if (text == null) { gifSearchEmojies.add("👍"); @@ -1112,14 +1158,14 @@ public class MessagesController extends BaseController implements NotificationCe } } + MessageObject newMsg = new_dialogMessage.get(value.id); if (currentDialog == null) { dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); } } } else { @@ -1129,33 +1175,43 @@ public class MessagesController extends BaseController implements NotificationCe if (oldMsg != null && oldMsg.deleted || oldMsg == null || currentDialog.top_message > 0) { if (value.top_message >= currentDialog.top_message) { dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject != null && messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } + dialogMessage.put(key, newMsg); if (oldMsg != null) { - dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(oldMsg.getId()); + } if (oldMsg.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } - } - } else { - MessageObject newMsg = new_dialogMessage.get(value.id); - if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { - dialogs_dict.put(key, value); - dialogMessage.put(key, newMsg); if (newMsg != null && newMsg.messageOwner.peer_id.channel_id == 0) { + if (oldMsg != null && oldMsg.getId() == newMsg.getId()) { + newMsg.deleted = oldMsg.deleted; + } dialogMessagesByIds.put(newMsg.getId(), newMsg); - if (newMsg != null && newMsg.messageOwner.random_id != 0) { + if (newMsg.messageOwner.random_id != 0) { dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); } } - dialogMessagesByIds.remove(oldMsg.getId()); + } + } else { + if (newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (oldMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(oldMsg.getId()); + } + if (newMsg != null) { + if (oldMsg.getId() == newMsg.getId()) { + newMsg.deleted = oldMsg.deleted; + } + if (newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + } if (oldMsg.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } @@ -1523,6 +1579,56 @@ public class MessagesController extends BaseController implements NotificationCe } break; } + case "emojies_sounds": { + try { + HashMap newEmojies = new HashMap<>(); + if (value.value instanceof TLRPC.TL_jsonObject) { + TLRPC.TL_jsonObject jsonObject = (TLRPC.TL_jsonObject) value.value; + for (int b = 0, N2 = jsonObject.value.size(); b < N2; b++) { + TLRPC.TL_jsonObjectValue val = jsonObject.value.get(b); + if (val.value instanceof TLRPC.TL_jsonObject) { + TLRPC.TL_jsonObject jsonObject2 = (TLRPC.TL_jsonObject) val.value; + long i = 0; + long ah = 0; + String fr = null; + for (int c = 0, N3 = jsonObject2.value.size(); c < N3; c++) { + TLRPC.TL_jsonObjectValue val2 = jsonObject2.value.get(c); + if (val2.value instanceof TLRPC.TL_jsonString) { + if ("id".equals(val2.key)) { + i = Utilities.parseLong(((TLRPC.TL_jsonString) val2.value).value); + } else if ("access_hash".equals(val2.key)) { + ah = Utilities.parseLong(((TLRPC.TL_jsonString) val2.value).value); + } else if ("file_reference_base64".equals(val2.key)) { + fr = ((TLRPC.TL_jsonString) val2.value).value; + } + } + } + if (i != 0 && ah != 0 && fr != null) { + newEmojies.put(val.key.replace("\uFE0F", ""), new EmojiSound(i, ah, fr)); + } + } + } + } + if (!emojiSounds.equals(newEmojies)) { + emojiSounds = newEmojies; + SerializedData serializedData = new SerializedData(); + serializedData.writeInt32(emojiSounds.size()); + for (HashMap.Entry entry : emojiSounds.entrySet()) { + serializedData.writeString(entry.getKey()); + EmojiSound emojiSound = entry.getValue(); + serializedData.writeInt64(emojiSound.id); + serializedData.writeInt64(emojiSound.accessHash); + serializedData.writeByteArray(emojiSound.fileReference); + } + editor.putString("emojiSounds", Base64.encodeToString(serializedData.toByteArray(), Base64.DEFAULT)); + serializedData.cleanup(); + changed = true; + } + } catch (Exception e) { + FileLog.e(e); + } + break; + } } } if (changed) { @@ -1884,8 +1990,6 @@ public class MessagesController extends BaseController implements NotificationCe } if (bigSize != null) { user.photo.photo_big = bigSize.location; - } else if (smallSize != null) { - user.photo.photo_small = smallSize.location; } getMessagesStorage().clearUserPhotos(user.id); ArrayList users = new ArrayList<>(); @@ -2136,8 +2240,8 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().postNotificationName(NotificationCenter.dialogsNeedReload); } obj = dialogMessagesByIds.get(msgId); - dialogMessagesByIds.remove(msgId); if (obj != null) { + dialogMessagesByIds.remove(msgId); dialogMessagesByIds.put(newMsgId, obj); } int lowerId = (int) (long) did; @@ -2152,12 +2256,14 @@ public class MessagesController extends BaseController implements NotificationCe } } else if (id == NotificationCenter.updateMessageMedia) { TLRPC.Message message = (TLRPC.Message) args[0]; - MessageObject existMessageObject = dialogMessagesByIds.get(message.id); - if (existMessageObject != null) { - existMessageObject.messageOwner.media = message.media; - if (message.media.ttl_seconds != 0 && (message.media.photo instanceof TLRPC.TL_photoEmpty || message.media.document instanceof TLRPC.TL_documentEmpty)) { - existMessageObject.setType(); - getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + if (message.peer_id.channel_id == 0) { + MessageObject existMessageObject = dialogMessagesByIds.get(message.id); + if (existMessageObject != null) { + existMessageObject.messageOwner.media = message.media; + if (message.media.ttl_seconds != 0 && (message.media.photo instanceof TLRPC.TL_photoEmpty || message.media.document instanceof TLRPC.TL_documentEmpty)) { + existMessageObject.setType(); + getNotificationCenter().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + } } } } @@ -2179,7 +2285,7 @@ public class MessagesController extends BaseController implements NotificationCe editor = emojiPreferences.edit(); editor.putLong("lastGifLoadTime", 0).putLong("lastStickersLoadTime", 0).putLong("lastStickersLoadTimeMask", 0).putLong("lastStickersLoadTimeFavs", 0).commit(); editor = mainPreferences.edit(); - editor.remove("archivehint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("dcDomainName2").remove("webFileDatacenterId").remove("themehint").commit(); lastScheduledServerQueryTime.clear(); reloadingWebpages.clear(); @@ -2952,7 +3058,7 @@ public class MessagesController extends BaseController implements NotificationCe if (res.full_chat.stickerset != null) { getMediaDataController().getGroupStickerSetById(res.full_chat.stickerset); } - getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, res.full_chat, classGuid, false, null); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, res.full_chat, classGuid, false); if ((res.full_chat.flags & 2048) != 0) { TLRPC.Dialog dialog = dialogs_dict.get(-chat_id); if (dialog != null && dialog.folder_id != res.full_chat.folder_id) { @@ -3023,7 +3129,7 @@ public class MessagesController extends BaseController implements NotificationCe if (userFull.bot_info instanceof TLRPC.TL_botInfo) { getNotificationCenter().postNotificationName(NotificationCenter.botInfoDidLoad, userFull.bot_info, classGuid); } - getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, userFull, null); + getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, userFull); if ((userFull.flags & 2048) != 0) { TLRPC.Dialog dialog = dialogs_dict.get(user.id); if (dialog != null && dialog.folder_id != userFull.folder_id) { @@ -3128,7 +3234,7 @@ public class MessagesController extends BaseController implements NotificationCe if (dialogObj != null) { for (int a = 0; a < objects.size(); a++) { MessageObject obj = objects.get(a); - if (dialogObj != null && dialogObj.getId() == obj.getId()) { + if (dialogObj.getId() == obj.getId()) { dialogMessage.put(dialog_id, obj); if (obj.messageOwner.peer_id.channel_id == 0) { MessageObject obj2 = dialogMessagesByIds.get(obj.getId()); @@ -3970,13 +4076,13 @@ public class MessagesController extends BaseController implements NotificationCe } public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, final long dialogId, final int channelId, boolean forAll, boolean scheduled, long taskId, TLObject taskRequest) { - if ((messages == null || messages.isEmpty()) && taskRequest == null) { + if ((messages == null || messages.isEmpty()) && taskId == 0) { return; } ArrayList toSend = null; if (taskId == 0) { toSend = new ArrayList<>(); - for (int a = 0; a < messages.size(); a++) { + for (int a = 0, N = messages.size(); a < N; a++) { Integer mid = messages.get(a); if (mid > 0) { toSend.add(mid); @@ -4104,16 +4210,41 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void pinMessage(TLRPC.Chat chat, TLRPC.User user, int id, boolean notify) { + public void unpinAllMessages(TLRPC.Chat chat, TLRPC.User user) { + if (chat == null && user == null) { + return; + } + TLRPC.TL_messages_unpinAllMessages req = new TLRPC.TL_messages_unpinAllMessages(); + req.peer = getInputPeer(chat != null ? -chat.id : user.id); + getConnectionsManager().sendRequest(req, (response, error) -> { + if (response != null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (ChatObject.isChannel(chat)) { + processNewChannelDifferenceParams(res.pts, res.pts_count, chat.id); + } else { + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + ArrayList ids = new ArrayList<>(); + getMessagesStorage().updatePinnedMessages(chat != null ? -chat.id : user.id, null, false, 0, 0, false, null); + } + }); + } + + public void pinMessage(TLRPC.Chat chat, TLRPC.User user, int id, boolean unpin, boolean oneSide, boolean notify) { if (chat == null && user == null) { return; } TLRPC.TL_messages_updatePinnedMessage req = new TLRPC.TL_messages_updatePinnedMessage(); req.peer = getInputPeer(chat != null ? -chat.id : user.id); req.id = id; + req.unpin = unpin; req.silent = !notify; + req.pm_oneside = oneSide; getConnectionsManager().sendRequest(req, (response, error) -> { if (error == null) { + ArrayList ids = new ArrayList<>(); + ids.add(id); + getMessagesStorage().updatePinnedMessages(chat != null ? -chat.id : user.id, ids, !unpin, -1, 0, false, null); TLRPC.Updates updates = (TLRPC.Updates) response; processUpdates(updates, false); } @@ -4345,11 +4476,15 @@ public class MessagesController extends BaseController implements NotificationCe dialogMessage.remove(dialog.id); if (object != null) { lastMessageId = object.getId(); - dialogMessagesByIds.remove(object.getId()); + if (object.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(object.getId()); + } } else { lastMessageId = dialog.top_message; object = dialogMessagesByIds.get(dialog.top_message); - dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(dialog.top_message); + } } if (object != null && object.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(object.messageOwner.random_id); @@ -4515,7 +4650,7 @@ public class MessagesController extends BaseController implements NotificationCe } req.unsave = false; getConnectionsManager().sendRequest(req, (response, error) -> { - if (error != null && FileRefController.isFileRefError(error.text) && parentObject != null) { + if (error != null && FileRefController.isFileRefError(error.text)) { getFileRefController().requestReference(parentObject, req); } }); @@ -4536,7 +4671,7 @@ public class MessagesController extends BaseController implements NotificationCe req.unsave = false; req.attached = asMask; getConnectionsManager().sendRequest(req, (response, error) -> { - if (error != null && FileRefController.isFileRefError(error.text) && parentObject != null) { + if (error != null && FileRefController.isFileRefError(error.text)) { getFileRefController().requestReference(parentObject, req); } }); @@ -4565,29 +4700,36 @@ public class MessagesController extends BaseController implements NotificationCe })); } - public void processChatInfo(int chat_id, final TLRPC.ChatFull info, final ArrayList usersArr, final boolean fromCache, boolean force, final boolean byChannelUsers, final MessageObject pinnedMessageObject) { + public void processChatInfo(int chatId, final TLRPC.ChatFull info, final ArrayList usersArr, final boolean fromCache, boolean force, final boolean byChannelUsers, ArrayList pinnedMessages, HashMap pinnedMessagesMap, int totalPinnedCount, boolean pinnedEndReached) { AndroidUtilities.runOnUIThread(() -> { - if (fromCache && chat_id > 0 && !byChannelUsers) { - loadFullChat(chat_id, 0, force); + if (fromCache && chatId > 0 && !byChannelUsers) { + loadFullChat(chatId, 0, force); } if (info != null) { - if (fullChats.get(chat_id) == null) { - fullChats.put(chat_id, info); + if (fullChats.get(chatId) == null) { + fullChats.put(chatId, info); } putUsers(usersArr, fromCache); if (info.stickerset != null) { getMediaDataController().getGroupStickerSetById(info.stickerset); } - getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, byChannelUsers, pinnedMessageObject); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, byChannelUsers); + } + if (pinnedMessages != null) { + getNotificationCenter().postNotificationName(NotificationCenter.pinnedInfoDidLoad, (long) -chatId, pinnedMessages, pinnedMessagesMap, totalPinnedCount, pinnedEndReached); } }); } public void loadUserInfo(TLRPC.User user, boolean force, int classGuid) { - getMessagesStorage().loadUserInfo(user, force, classGuid); + loadUserInfo(user, force, classGuid, 0); } - public void processUserInfo(TLRPC.User user, final TLRPC.UserFull info, final boolean fromCache, boolean force, final MessageObject pinnedMessageObject, int classGuid) { + public void loadUserInfo(TLRPC.User user, boolean force, int classGuid, int fromMessageId) { + getMessagesStorage().loadUserInfo(user, force, classGuid, fromMessageId); + } + + public void processUserInfo(TLRPC.User user, TLRPC.UserFull info, boolean fromCache, boolean force, int classGuid, ArrayList pinnedMessages, HashMap pinnedMessagesMap, int totalPinnedCount, boolean pinnedEndReached) { AndroidUtilities.runOnUIThread(() -> { if (fromCache) { loadFullUser(user, classGuid, force); @@ -4601,7 +4743,10 @@ public class MessagesController extends BaseController implements NotificationCe blockePeers.delete(user.id); } } - getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, info, pinnedMessageObject); + getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, user.id, info); + } + if (pinnedMessages != null) { + getNotificationCenter().postNotificationName(NotificationCenter.pinnedInfoDidLoad, (long) user.id, pinnedMessages, pinnedMessagesMap, totalPinnedCount, pinnedEndReached); } }); } @@ -5413,15 +5558,28 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void sendTyping(long dialogId, int threadMsgId, int action, int classGuid) { - if (NekoConfig.disableChatAction) return; + public boolean sendTyping(long dialogId, int threadMsgId, int action, int classGuid) { + if (NekoConfig.disableChatAction) return false; if (action < 0 || action >= sendingTypings.length || dialogId == 0) { - return; + return false; } int lower_part = (int) dialogId; if (lower_part < 0) { if (ChatObject.shouldSendAnonymously(getChat(-lower_part))) { - return; + return false; + } + } else { + TLRPC.User user = getUser(lower_part); + if (user != null) { + if (user.id == getUserConfig().getClientUserId()) { + return false; + } + if (user.status != null && user.status.expires != -100 && !onlinePrivacy.containsKey(user.id)) { + int time = getConnectionsManager().getCurrentTime(); + if (user.status.expires <= time - 30) { + return false; + } + } } } LongSparseArray> dialogs = sendingTypings[action]; @@ -5433,7 +5591,7 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.put(dialogId, threads = new SparseArray<>()); } if (threads.get(threadMsgId) != null) { - return; + return false; } int high_id = (int) (dialogId >> 32); if (lower_part != 0) { @@ -5446,11 +5604,11 @@ public class MessagesController extends BaseController implements NotificationCe if (req.peer instanceof TLRPC.TL_inputPeerChannel) { TLRPC.Chat chat = getChat(req.peer.channel_id); if (chat == null || !chat.megagroup) { - return; + return false; } } if (req.peer == null) { - return; + return false; } if (action == 0) { req.action = new TLRPC.TL_sendMessageTypingAction(); @@ -5480,7 +5638,7 @@ public class MessagesController extends BaseController implements NotificationCe } } else { if (action != 0) { - return; + return false; } TLRPC.EncryptedChat chat = getEncryptedChat(high_id); if (chat.auth_key != null && chat.auth_key.length > 1 && chat instanceof TLRPC.TL_encryptedChat) { @@ -5496,6 +5654,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + return true; } protected void removeDeletedMessagesFromArray(final long dialog_id, ArrayList messages) { @@ -5513,24 +5672,24 @@ public class MessagesController extends BaseController implements NotificationCe } } - public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, boolean isChannel, boolean scheduled, int threadMessageId, int replyFirstUnread, int loadIndex) { - loadMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, isChannel, scheduled, threadMessageId, loadIndex, threadMessageId != 0 ? replyFirstUnread : 0, 0, 0, false, 0); + public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, boolean isChannel, int mode, int threadMessageId, int replyFirstUnread, int loadIndex) { + loadMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, isChannel, mode, threadMessageId, loadIndex, threadMessageId != 0 ? replyFirstUnread : 0, 0, 0, false, 0); } - public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, boolean isChannel, boolean scheduled, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount) { - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, isChannel, scheduled, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true); + public void loadMessages(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int midDate, int classGuid, int load_type, int last_message_id, boolean isChannel, int mode, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount) { + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, fromCache, midDate, classGuid, load_type, last_message_id, isChannel, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount, true); } - private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int minDate, int classGuid, int load_type, int last_message_id, boolean isChannel, boolean scheduled, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean loadDialog) { + private void loadMessagesInternal(long dialogId, long mergeDialogId, boolean loadInfo, int count, int max_id, int offset_date, boolean fromCache, int minDate, int classGuid, int load_type, int last_message_id, boolean isChannel, int mode, int threadMessageId, int loadIndex, int first_unread, int unread_count, int last_date, boolean queryFromServer, int mentionsCount, boolean loadDialog) { if (BuildVars.LOGS_ENABLED) { - FileLog.d("load messages in chat " + dialogId + " count " + count + " max_id " + max_id + " cache " + fromCache + " mindate = " + minDate + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " scheduled " + scheduled + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); + FileLog.d("load messages in chat " + dialogId + " count " + count + " max_id " + max_id + " cache " + fromCache + " mindate = " + minDate + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " mode " + mode + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); } int lower_part = (int) dialogId; - if (threadMessageId == 0 && (fromCache || lower_part == 0)) { - getMessagesStorage().getMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, minDate, classGuid, load_type, isChannel, scheduled, threadMessageId, loadIndex); + if (threadMessageId == 0 && mode != 2 && (fromCache || lower_part == 0)) { + getMessagesStorage().getMessages(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, minDate, classGuid, load_type, isChannel, mode == 1, threadMessageId, loadIndex); } else { if (threadMessageId != 0) { - if (scheduled) { + if (mode != 0) { return; } TLRPC.TL_messages_getReplies req = new TLRPC.TL_messages_getReplies(); @@ -5584,13 +5743,15 @@ public class MessagesController extends BaseController implements NotificationCe } } } - processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, fnid, last_message_id, unread_count, last_date, load_type, isChannel, false, false, threadMessageId, loadIndex, queryFromServer, mentionsCount); + processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, fnid, last_message_id, unread_count, last_date, load_type, isChannel, false, 0, threadMessageId, loadIndex, queryFromServer, mentionsCount); } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); } }); getConnectionsManager().bindRequestToGuid(reqId, classGuid); - } else if (scheduled) { + } else if (mode == 2) { + + } else if (mode == 1) { TLRPC.TL_messages_getScheduledHistory req = new TLRPC.TL_messages_getScheduledHistory(); req.peer = getInputPeer(lower_part); req.hash = minDate; @@ -5611,7 +5772,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } - processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, true, threadMessageId, loadIndex, queryFromServer, mentionsCount); + processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, mode, threadMessageId, loadIndex, queryFromServer, mentionsCount); } }); getConnectionsManager().bindRequestToGuid(reqId, classGuid); @@ -5638,7 +5799,7 @@ public class MessagesController extends BaseController implements NotificationCe getMessagesStorage().putDialogs(dialogs, 0); } - loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, dialog.top_message, isChannel, false, threadMessageId, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false); + loadMessagesInternal(dialogId, mergeDialogId, loadInfo, count, max_id, offset_date, false, minDate, classGuid, load_type, dialog.top_message, isChannel, 0, threadMessageId, loadIndex, first_unread, dialog.unread_count, last_date, queryFromServer, dialog.unread_mentions_count, false); } } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); @@ -5686,7 +5847,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } - processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, false, threadMessageId, loadIndex, queryFromServer, mentionsCount); + processLoadedMessages(res, dialogId, mergeDialogId, count, mid, offset_date, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, isChannel, false, 0, threadMessageId, loadIndex, queryFromServer, mentionsCount); } else { AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.loadingMessagesFailed, classGuid, req, error)); } @@ -5745,7 +5906,7 @@ public class MessagesController extends BaseController implements NotificationCe } public void processLoadedMessages(TLRPC.messages_Messages messagesRes, long dialogId, long mergeDialogId, int count, int max_id, int offset_date, boolean isCache, int classGuid, - int first_unread, int last_message_id, int unread_count, int last_date, int load_type, boolean isChannel, boolean isEnd, boolean scheduled, int threadMessageId, int loadIndex, boolean queryFromServer, int mentionsCount) { + int first_unread, int last_message_id, int unread_count, int last_date, int load_type, boolean isChannel, boolean isEnd, int mode, int threadMessageId, int loadIndex, boolean queryFromServer, int mentionsCount) { if (BuildVars.LOGS_ENABLED) { FileLog.d("processLoadedMessages size " + messagesRes.messages.size() + " in chat " + dialogId + " count " + count + " max_id " + max_id + " cache " + isCache + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " isChannel " + isChannel + " index " + loadIndex + " firstUnread " + first_unread + " unread_count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); } @@ -5753,7 +5914,7 @@ public class MessagesController extends BaseController implements NotificationCe boolean isMegagroup = false; if (messagesRes instanceof TLRPC.TL_messages_channelMessages) { int channelId = -(int) dialogId; - if (!scheduled && threadMessageId == 0) { + if (mode == 0 && threadMessageId == 0) { int channelPts = channelsPts.get(channelId); if (channelPts == 0) { channelPts = getMessagesStorage().getChannelPtsSync(channelId); @@ -5783,9 +5944,11 @@ public class MessagesController extends BaseController implements NotificationCe } boolean isInitialLoading = offset_date == 0 && max_id == 0; - if (high_id != 1 && lower_id != 0 && isCache && ((messagesRes.messages.size() == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 60 * 1000)) || scheduled && (SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000)) { + if (high_id != 1 && lower_id != 0 && isCache && ((messagesRes.messages.size() == 0 && (!isInitialLoading || (SystemClock.elapsedRealtime() - lastServerQueryTime.get(dialogId, 0L)) > 60 * 1000)) || mode == 1 && (SystemClock.elapsedRealtime() - lastScheduledServerQueryTime.get(dialogId, 0L)) > 60 * 1000)) { int hash; - if (scheduled) { + if (mode == 2) { + hash = 0; + } else if (mode == 1) { lastScheduledServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); long h = 0; for (int a = 0, N = messagesRes.messages.size(); a < N; a++) { @@ -5802,7 +5965,7 @@ public class MessagesController extends BaseController implements NotificationCe lastServerQueryTime.put(dialogId, SystemClock.elapsedRealtime()); hash = 0; } - AndroidUtilities.runOnUIThread(() -> loadMessages(dialogId, mergeDialogId, false, count, load_type == 2 && queryFromServer ? first_unread : max_id, offset_date, false, hash, classGuid, load_type, last_message_id, isChannel, scheduled, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount)); + AndroidUtilities.runOnUIThread(() -> loadMessages(dialogId, mergeDialogId, false, count, load_type == 2 && queryFromServer ? first_unread : max_id, offset_date, false, hash, classGuid, load_type, last_message_id, isChannel, mode, threadMessageId, loadIndex, first_unread, unread_count, last_date, queryFromServer, mentionsCount)); if (messagesRes.messages.isEmpty()) { return; } @@ -5837,7 +6000,7 @@ public class MessagesController extends BaseController implements NotificationCe message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; } - if (!scheduled) { + if (mode == 0) { if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { TLRPC.User user = usersDict.get(message.action.user_id); if (user != null && user.bot) { @@ -5857,7 +6020,7 @@ public class MessagesController extends BaseController implements NotificationCe } } if (threadMessageId == 0) { - getMessagesStorage().putMessages(messagesRes, dialogId, load_type, max_id, createDialog, scheduled); + getMessagesStorage().putMessages(messagesRes, dialogId, load_type, max_id, createDialog, mode == 1); } } @@ -5869,7 +6032,7 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.Message message = messagesRes.messages.get(a); message.dialog_id = dialogId; MessageObject messageObject = new MessageObject(currentAccount, message, usersDict, chatsDict, true, true); - messageObject.scheduled = scheduled; + messageObject.scheduled = mode == 1; objects.add(messageObject); if (isCache) { if (message.legacy && message.layer < TLRPC.LAYER) { @@ -5897,7 +6060,7 @@ public class MessagesController extends BaseController implements NotificationCe putUsers(messagesRes.users, isCache); putChats(messagesRes.chats, isCache); int first_unread_final; - if (scheduled) { + if (mode == 1) { first_unread_final = 0; } else { first_unread_final = Integer.MAX_VALUE; @@ -5913,22 +6076,22 @@ public class MessagesController extends BaseController implements NotificationCe first_unread_final = first_unread; } } - if (scheduled && count == 1) { + if (mode == 1 && count == 1) { getNotificationCenter().postNotificationName(NotificationCenter.scheduledMessagesUpdated, dialogId, objects.size()); } if ((int) dialogId != 0) { int finalFirst_unread_final = first_unread_final; - getMediaDataController().loadReplyMessagesForMessages(objects, dialogId, scheduled, () -> getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, finalFirst_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, scheduled)); + getMediaDataController().loadReplyMessagesForMessages(objects, dialogId, mode == 1, () -> getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, finalFirst_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, mode)); } else { - getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, scheduled); + getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialogId, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, isEnd, classGuid, loadIndex, max_id, mentionsCount, mode); } if (!messagesToReload.isEmpty()) { - reloadMessages(messagesToReload, dialogId, scheduled); + reloadMessages(messagesToReload, dialogId, mode == 1); } if (!webpagesToReload.isEmpty()) { - reloadWebPages(dialogId, webpagesToReload, scheduled); + reloadWebPages(dialogId, webpagesToReload, mode == 1); } }); } @@ -6222,9 +6385,7 @@ public class MessagesController extends BaseController implements NotificationCe SharedPreferences.Editor editor1 = null; if (preferences.contains("EnableGroup")) { boolean enabled = preferences.getBoolean("EnableGroup", true); - if (editor1 == null) { - editor1 = preferences.edit(); - } + editor1 = preferences.edit(); if (!enabled) { editor1.putInt("EnableGroup2", Integer.MAX_VALUE); editor1.putInt("EnableChannel2", Integer.MAX_VALUE); @@ -6252,7 +6413,7 @@ public class MessagesController extends BaseController implements NotificationCe req.peer = new TLRPC.TL_inputNotifyChats(); } else if (a == 1) { req.peer = new TLRPC.TL_inputNotifyUsers(); - } else if (a == 2) { + } else { req.peer = new TLRPC.TL_inputNotifyBroadcasts(); } final int type = a; @@ -6289,7 +6450,7 @@ public class MessagesController extends BaseController implements NotificationCe if ((notify_settings.flags & 4) != 0) { editor.putInt("EnableAll2", notify_settings.mute_until); } - } else if (type == 2) { + } else { if ((notify_settings.flags & 1) != 0) { editor.putBoolean("EnablePreviewChannel", notify_settings.show_previews); } @@ -6619,7 +6780,9 @@ public class MessagesController extends BaseController implements NotificationCe MessageObject messageObject = dialogMessage.get(oldDialog.id); dialogMessage.remove(oldDialog.id); if (messageObject != null) { - dialogMessagesByIds.remove(messageObject.getId()); + if (messageObject.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(messageObject.getId()); + } if (messageObject.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(messageObject.messageOwner.random_id); } @@ -6750,11 +6913,10 @@ public class MessagesController extends BaseController implements NotificationCe long did = cursor.longValue(0); int folder_id = cursor.intValue(1); TLRPC.Dialog dialog = dialogHashMap.get(did); - if (dialog.folder_id != folder_id) { - continue; - } - dialogHashMap.remove(did); if (dialog != null) { + if (dialog.folder_id != folder_id) { + continue; + } dialogsRes.dialogs.remove(dialog); for (int a = 0; a < dialogsRes.messages.size(); a++) { TLRPC.Message message = dialogsRes.messages.get(a); @@ -6769,6 +6931,7 @@ public class MessagesController extends BaseController implements NotificationCe } } } + dialogHashMap.remove(did); } cursor.dispose(); if (BuildVars.LOGS_ENABLED) { @@ -7045,7 +7208,7 @@ public class MessagesController extends BaseController implements NotificationCe if (!chat.megagroup) { allowCheck = false; } - if (chat.left && (promoDialogId == 0 || promoDialogId != d.id)) { + if (ChatObject.isNotInChat(chat) && (promoDialogId == 0 || promoDialogId != d.id)) { continue; } } @@ -7155,15 +7318,15 @@ public class MessagesController extends BaseController implements NotificationCe if (value.folder_id != folderId) { archivedDialogsCount++; } + MessageObject newMsg = new_dialogMessage.get(value.id); if (currentDialog == null) { added = true; dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); } } } else { @@ -7176,33 +7339,42 @@ public class MessagesController extends BaseController implements NotificationCe if (oldMsg != null && oldMsg.deleted || oldMsg == null || currentDialog.top_message > 0) { if (value.top_message >= currentDialog.top_message) { dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - if (messageObject != null && messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } + dialogMessage.put(key, newMsg); if (oldMsg != null) { - dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(oldMsg.getId()); + } if (oldMsg.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } - } - } else { - MessageObject newMsg = new_dialogMessage.get(value.id); - if (oldMsg.deleted || newMsg == null && (oldMsg == null || oldMsg.isSent()) || newMsg != null && newMsg.messageOwner.date > oldMsg.messageOwner.date) { - dialogs_dict.put(key, value); - dialogMessage.put(key, newMsg); - if (newMsg != null && newMsg.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(newMsg.getId(), newMsg); - if (newMsg != null && newMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + if (newMsg != null) { + if (oldMsg != null && oldMsg.getId() == newMsg.getId()) { + newMsg.deleted = oldMsg.deleted; + } + if (newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + } + } + } else { + if (newMsg == null && oldMsg.isSent() || newMsg != null && newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (oldMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(oldMsg.getId()); + } + if (newMsg != null) { + if (newMsg.messageOwner.peer_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); } @@ -7496,6 +7668,9 @@ public class MessagesController extends BaseController implements NotificationCe } req.limit = 1; checkingLastMessagesDialogs.put(lower_id, true); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("checkLastDialogMessage for " + lower_id); + } final long newTaskId; if (taskId == 0) { @@ -7530,6 +7705,9 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; removeDeletedMessagesFromArray(lower_id, res.messages); if (!res.messages.isEmpty()) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("checkLastDialogMessage for " + lower_id + " has message"); + } TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); TLRPC.Message newMessage = res.messages.get(0); TLRPC.Dialog newDialog = new TLRPC.TL_dialog(); @@ -7552,16 +7730,27 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.dialogs.add(newDialog); dialogs.messages.addAll(res.messages); dialogs.count = 1; - processDialogsUpdate(dialogs, null); + processDialogsUpdate(dialogs, null, false); getMessagesStorage().putMessages(res.messages, true, true, false, getDownloadController().getAutodownloadMask(), true, false); } else { AndroidUtilities.runOnUIThread(() -> { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("checkLastDialogMessage for " + lower_id + " has not message"); + } if (getMediaDataController().getDraft(dialog.id, 0) == null) { TLRPC.Dialog currentDialog = dialogs_dict.get(dialog.id); if (currentDialog == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("checkLastDialogMessage for " + lower_id + " current dialog not found"); + } getMessagesStorage().isDialogHasTopMessage(dialog.id, () -> deleteDialog(dialog.id, 3)); - } else if (currentDialog.top_message == 0) { - deleteDialog(dialog.id, 3); + } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("checkLastDialogMessage for " + lower_id + " current dialog top message " + currentDialog.top_message); + } + if (currentDialog.top_message == 0) { + deleteDialog(dialog.id, 3); + } } } }); @@ -7574,7 +7763,7 @@ public class MessagesController extends BaseController implements NotificationCe }); } - public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats) { + public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats, boolean fromCache) { Utilities.stageQueue.postRunnable(() -> { final LongSparseArray new_dialogs_dict = new LongSparseArray<>(); final LongSparseArray new_dialogMessage = new LongSparseArray<>(); @@ -7596,7 +7785,7 @@ public class MessagesController extends BaseController implements NotificationCe if (promoDialogId == 0 || promoDialogId != message.dialog_id) { if (message.peer_id.channel_id != 0) { TLRPC.Chat chat = chatsDict.get(message.peer_id.channel_id); - if (chat != null && chat.left) { + if (chat != null && ChatObject.isNotInChat(chat)) { continue; } } else if (message.peer_id.chat_id != 0) { @@ -7615,7 +7804,7 @@ public class MessagesController extends BaseController implements NotificationCe if (promoDialogId == 0 || promoDialogId != d.id) { if (DialogObject.isChannel(d)) { TLRPC.Chat chat = chatsDict.get(-(int) d.id); - if (chat != null && chat.left) { + if (chat != null && ChatObject.isNotInChat(chat)) { continue; } } else if ((int) d.id < 0) { @@ -7653,24 +7842,41 @@ public class MessagesController extends BaseController implements NotificationCe for (int a = 0; a < new_dialogs_dict.size(); a++) { long key = new_dialogs_dict.keyAt(a); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate " + key); + } TLRPC.Dialog value = new_dialogs_dict.valueAt(a); TLRPC.Dialog currentDialog = dialogs_dict.get(key); + MessageObject newMsg = new_dialogMessage.get(value.id); if (currentDialog == null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate dialog null"); + } int offset = nextDialogsCacheOffset.get(value.folder_id, 0) + 1; nextDialogsCacheOffset.put(value.folder_id, offset); dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject == null) { - checkLastDialogMessage(value, null, 0); - } else if (messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, messageObject.messageOwner.date); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + dialogMessage.put(key, newMsg); + if (newMsg == null) { + if (fromCache) { + checkLastDialogMessage(value, null, 0); + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate new message is null"); + } + } else if (newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, newMsg.messageOwner.date); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate new message not null"); } } } else { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate dialog not null"); + } currentDialog.unread_count = value.unread_count; if (currentDialog.unread_mentions_count != value.unread_mentions_count) { currentDialog.unread_mentions_count = value.unread_mentions_count; @@ -7679,41 +7885,58 @@ public class MessagesController extends BaseController implements NotificationCe } } MessageObject oldMsg = dialogMessage.get(key); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate oldMsg " + oldMsg + " old top_message = " + currentDialog.top_message + " new top_message = " + value.top_message); + FileLog.d("processDialogsUpdate oldMsgDeleted " + (oldMsg != null && oldMsg.deleted)); + } if (oldMsg == null || currentDialog.top_message > 0) { if (oldMsg != null && oldMsg.deleted || value.top_message > currentDialog.top_message) { dialogs_dict.put(key, value); - MessageObject messageObject = new_dialogMessage.get(value.id); - dialogMessage.put(key, messageObject); - if (messageObject != null && messageObject.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(messageObject.getId(), messageObject); - dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, messageObject.messageOwner.date); - if (messageObject.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); - } - } - if (oldMsg != null) { + dialogMessage.put(key, newMsg); + if (oldMsg != null && oldMsg.messageOwner.peer_id.channel_id == 0) { dialogMessagesByIds.remove(oldMsg.getId()); if (oldMsg.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); } } - if (messageObject == null) { - checkLastDialogMessage(value, null, 0); + if (newMsg != null) { + if (oldMsg != null && oldMsg.getId() == newMsg.getId()) { + newMsg.deleted = oldMsg.deleted; + } + if (newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, newMsg.messageOwner.date); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + } + } + if (fromCache && newMsg == null) { + checkLastDialogMessage(value, null, 0); + if (BuildVars.LOGS_ENABLED) { + FileLog.d("processDialogsUpdate new message is null"); } } } else { - MessageObject newMsg = new_dialogMessage.get(value.id); if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { dialogs_dict.put(key, value); dialogMessage.put(key, newMsg); - if (newMsg != null && newMsg.messageOwner.peer_id.channel_id == 0) { - dialogMessagesByIds.put(newMsg.getId(), newMsg); - dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, newMsg.messageOwner.date); - if (newMsg.messageOwner.random_id != 0) { - dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + if (oldMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(oldMsg.getId()); + } + if (newMsg != null) { + if (oldMsg.getId() == newMsg.getId()) { + newMsg.deleted = oldMsg.deleted; + } + if (newMsg.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + dialogsLoadedTillDate = Math.min(dialogsLoadedTillDate, newMsg.messageOwner.date); + 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); } @@ -8377,7 +8600,7 @@ public class MessagesController extends BaseController implements NotificationCe AndroidUtilities.runOnUIThread(() -> { info.about = about; getMessagesStorage().updateChatInfo(info, false); - getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false, null); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false); }); } }, ConnectionsManager.RequestFlagInvokeAfter); @@ -8533,7 +8756,7 @@ public class MessagesController extends BaseController implements NotificationCe newPart.date = getConnectionsManager().getCurrentTime(); info.participants.participants.add(0, newPart); getMessagesStorage().updateChatInfo(info, true); - getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false, null); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false); getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHAT_MEMBERS); } } @@ -8620,7 +8843,7 @@ public class MessagesController extends BaseController implements NotificationCe } if (changed) { getMessagesStorage().updateChatInfo(info, true); - getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false, null); + getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false); } getNotificationCenter().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHAT_MEMBERS); } @@ -9208,7 +9431,7 @@ public class MessagesController extends BaseController implements NotificationCe } inputChannel = getInputChannel(chat); } - if (inputChannel == null || inputChannel.access_hash == 0) { + if (inputChannel.access_hash == 0) { if (taskId != 0) { getMessagesStorage().removePendingTask(taskId); } @@ -9738,15 +9961,11 @@ public class MessagesController extends BaseController implements NotificationCe TLRPC.TL_dialogPeer dialogPeer = (TLRPC.TL_dialogPeer) peer; long did; if (dialogPeer.peer.user_id != 0) { - if (dialogPeer.peer.user_id != 0) { - did = dialogPeer.peer.user_id; - } else if (dialogPeer.peer.chat_id != 0) { - did = -dialogPeer.peer.chat_id; - } else { - did = -dialogPeer.peer.channel_id; - } + did = dialogPeer.peer.user_id; + } else if (dialogPeer.peer.chat_id != 0) { + did = -dialogPeer.peer.chat_id; } else { - did = 0; + did = -dialogPeer.peer.channel_id; } getMessagesStorage().setDialogUnread(did, true); TLRPC.Dialog dialog = dialogs_dict.get(did); @@ -10214,7 +10433,7 @@ public class MessagesController extends BaseController implements NotificationCe } else if (update instanceof TLRPC.TL_updateNewEncryptedMessage) { return 1; } else if (update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateDeleteChannelMessages || update instanceof TLRPC.TL_updateEditChannelMessage || - update instanceof TLRPC.TL_updateChannelWebPage) { + update instanceof TLRPC.TL_updateChannelWebPage || update instanceof TLRPC.TL_updatePinnedChannelMessages) { return 2; } else { return 3; @@ -10248,6 +10467,10 @@ public class MessagesController extends BaseController implements NotificationCe return ((TLRPC.TL_updateChannelTooLong) update).pts; } else if (update instanceof TLRPC.TL_updateFolderPeers) { return ((TLRPC.TL_updateFolderPeers) update).pts; + } else if (update instanceof TLRPC.TL_updatePinnedChannelMessages) { + return ((TLRPC.TL_updatePinnedChannelMessages) update).pts; + } else if (update instanceof TLRPC.TL_updatePinnedMessages) { + return ((TLRPC.TL_updatePinnedMessages) update).pts; } else { return 0; } @@ -10278,6 +10501,10 @@ public class MessagesController extends BaseController implements NotificationCe return ((TLRPC.TL_updateReadMessagesContents) update).pts_count; } else if (update instanceof TLRPC.TL_updateFolderPeers) { return ((TLRPC.TL_updateFolderPeers) update).pts_count; + } else if (update instanceof TLRPC.TL_updatePinnedChannelMessages) { + return ((TLRPC.TL_updatePinnedChannelMessages) update).pts_count; + } else if (update instanceof TLRPC.TL_updatePinnedMessages) { + return ((TLRPC.TL_updatePinnedMessages) update).pts_count; } else { return 0; } @@ -10304,8 +10531,6 @@ public class MessagesController extends BaseController implements NotificationCe return ((TLRPC.TL_updateChannelMessageForwards) update).channel_id; } else if (update instanceof TLRPC.TL_updateChannelTooLong) { return ((TLRPC.TL_updateChannelTooLong) update).channel_id; - } else if (update instanceof TLRPC.TL_updateChannelPinnedMessage) { - return ((TLRPC.TL_updateChannelPinnedMessage) update).channel_id; } else if (update instanceof TLRPC.TL_updateChannelReadMessagesContents) { return ((TLRPC.TL_updateChannelReadMessagesContents) update).channel_id; } else if (update instanceof TLRPC.TL_updateChannelAvailableMessages) { @@ -10324,6 +10549,8 @@ public class MessagesController extends BaseController implements NotificationCe return ((TLRPC.TL_updateReadChannelDiscussionOutbox) update).channel_id; } else if (update instanceof TLRPC.TL_updateChannelUserTyping) { return ((TLRPC.TL_updateChannelUserTyping) update).channel_id; + } else if (update instanceof TLRPC.TL_updatePinnedChannelMessages) { + return ((TLRPC.TL_updatePinnedChannelMessages) update).channel_id; } else { if (BuildVars.LOGS_ENABLED) { FileLog.e("trying to get unknown update channel_id for " + update); @@ -10618,7 +10845,7 @@ public class MessagesController extends BaseController implements NotificationCe if (BuildVars.LOGS_ENABLED) { FileLog.d(update + " need get diff, pts: " + getMessagesStorage().getLastPtsValue() + " " + updatesNew.pts + " count = " + updatesNew.pts_count); } - if (gettingDifference || updatesStartWaitTimePts == 0 || updatesStartWaitTimePts != 0 && Math.abs(System.currentTimeMillis() - updatesStartWaitTimePts) <= 1500) { + if (gettingDifference || updatesStartWaitTimePts == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimePts) <= 1500) { if (updatesStartWaitTimePts == 0) { updatesStartWaitTimePts = System.currentTimeMillis(); } @@ -10654,7 +10881,7 @@ public class MessagesController extends BaseController implements NotificationCe if (BuildVars.LOGS_ENABLED) { FileLog.d(update + " need get diff, qts: " + getMessagesStorage().getLastQtsValue() + " " + updatesNew.pts); } - if (gettingDifference || updatesStartWaitTimeQts == 0 || updatesStartWaitTimeQts != 0 && Math.abs(System.currentTimeMillis() - updatesStartWaitTimeQts) <= 1500) { + if (gettingDifference || updatesStartWaitTimeQts == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimeQts) <= 1500) { if (updatesStartWaitTimeQts == 0) { updatesStartWaitTimeQts = System.currentTimeMillis(); } @@ -11048,7 +11275,7 @@ public class MessagesController extends BaseController implements NotificationCe ImageLoader.saveMessageThumbs(message); MessageObject.getDialogId(message); - if (baseUpdate instanceof TLRPC.TL_updateNewChannelMessage && message.reply_to != null) { + if (baseUpdate instanceof TLRPC.TL_updateNewChannelMessage && message.reply_to != null && !(message.action instanceof TLRPC.TL_messageActionPinMessage)) { if (channelReplies == null) { channelReplies = new SparseArray<>(); } @@ -11191,6 +11418,11 @@ public class MessagesController extends BaseController implements NotificationCe } else { markAsReadMessagesOutbox.put(update.peer.user_id, update.max_id); dialog_id = update.peer.user_id; + TLRPC.User user = getUser(update.peer.user_id); + if (user != null && user.status != null && user.status.expires <= 0 && Math.abs(getConnectionsManager().getCurrentTime() - date) < 30) { + onlinePrivacy.put(update.peer.user_id, date); + interfaceUpdateMask |= UPDATE_MASK_STATUS; + } } Integer value = dialogs_read_outbox_max.get(dialog_id); if (value == null) { @@ -11797,18 +12029,15 @@ public class MessagesController extends BaseController implements NotificationCe array.put(message.dialog_id, arr); } arr.add(obj); - } else if (baseUpdate instanceof TLRPC.TL_updateChannelPinnedMessage) { - TLRPC.TL_updateChannelPinnedMessage update = (TLRPC.TL_updateChannelPinnedMessage) baseUpdate; + } else if (baseUpdate instanceof TLRPC.TL_updatePinnedChannelMessages) { + TLRPC.TL_updatePinnedChannelMessages update = (TLRPC.TL_updatePinnedChannelMessages) baseUpdate; if (BuildVars.LOGS_ENABLED) { FileLog.d(baseUpdate + " channelId = " + update.channel_id); } - getMessagesStorage().updateChatPinnedMessage(update.channel_id, update.id); - } else if (baseUpdate instanceof TLRPC.TL_updateChatPinnedMessage) { - TLRPC.TL_updateChatPinnedMessage update = (TLRPC.TL_updateChatPinnedMessage) baseUpdate; - getMessagesStorage().updateChatPinnedMessage(update.chat_id, update.id); - } else if (baseUpdate instanceof TLRPC.TL_updateUserPinnedMessage) { - TLRPC.TL_updateUserPinnedMessage update = (TLRPC.TL_updateUserPinnedMessage) baseUpdate; - getMessagesStorage().updateUserPinnedMessage(update.user_id, update.id); + getMessagesStorage().updatePinnedMessages(-update.channel_id, update.messages, update.pinned, -1, 0, false, null); + } else if (baseUpdate instanceof TLRPC.TL_updatePinnedMessages) { + TLRPC.TL_updatePinnedMessages update = (TLRPC.TL_updatePinnedMessages) baseUpdate; + getMessagesStorage().updatePinnedMessages(MessageObject.getPeerId(update.peer), update.messages, update.pinned, -1, 0, false, null); } else if (baseUpdate instanceof TLRPC.TL_updateReadFeaturedStickers) { if (updatesOnMainThread == null) { updatesOnMainThread = new ArrayList<>(); @@ -12677,6 +12906,9 @@ public class MessagesController extends BaseController implements NotificationCe Integer id = arrayList.get(b); MessageObject obj = dialogMessagesByIds.get(id); if (obj != null) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("mark messages " + obj.getId() + " deleted"); + } obj.deleted = true; } } @@ -12800,7 +13032,13 @@ public class MessagesController extends BaseController implements NotificationCe return false; } - public CharSequence getPrintingString(long dialogId, int threadId) { + public CharSequence getPrintingString(long dialogId, int threadId, boolean isDialog) { + if (isDialog && (int) dialogId > 0) { + TLRPC.User user = getUser((int) dialogId); + if (user != null && user.status != null && user.status.expires < 0) { + return null; + } + } SparseArray threads = printingStrings.get(dialogId); if (threads == null) { return null; @@ -12946,7 +13184,9 @@ public class MessagesController extends BaseController implements NotificationCe dialogs.remove(dialog); } MessageObject object = dialogMessagesByIds.get(dialog.top_message); - dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(dialog.top_message); + } if (object != null && object.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(object.messageOwner.random_id); } @@ -12961,7 +13201,7 @@ public class MessagesController extends BaseController implements NotificationCe if (dialog == null) { TLRPC.Chat chat = getChat(channelId); - if (channelId != 0 && chat == null || chat != null && ChatObject.isNotInChat(chat)) { + if (channelId != 0 && chat == null || chat != null && (ChatObject.isNotInChat(chat) || chat.min)) { return false; } if (BuildVars.LOGS_ENABLED) { @@ -13003,7 +13243,9 @@ public class MessagesController extends BaseController implements NotificationCe (dialog.top_message < 0 && lastMessage.getId() < 0 && lastMessage.getId() < dialog.top_message) || dialogMessage.indexOfKey(uid) < 0 || dialog.top_message < 0 || dialog.last_message_date <= lastMessage.messageOwner.date) { MessageObject object = dialogMessagesByIds.get(dialog.top_message); - dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.peer_id.channel_id == 0) { + dialogMessagesByIds.remove(dialog.top_message); + } if (object != null && object.messageOwner.random_id != 0) { dialogMessagesByRandomIds.remove(object.messageOwner.random_id); } @@ -13182,7 +13424,7 @@ public class MessagesController extends BaseController implements NotificationCe } dialogsCanAddUsers.add(d); dialogsGroupsOnly.add(d); - } else if (lower_id > 0 && lower_id != selfId) { + } else if (lower_id != selfId) { dialogsUsersOnly.add(d); if (!UserObject.isReplyUser(lower_id)) { dialogsForBlock.add(d); @@ -13299,7 +13541,7 @@ public class MessagesController extends BaseController implements NotificationCe String reason = null; if (chat != null) { reason = getRestrictionReason(chat.restriction_reason); - } else if (user != null) { + } else { reason = getRestrictionReason(user.restriction_reason); } if (reason != null) { @@ -13343,9 +13585,7 @@ public class MessagesController extends BaseController implements NotificationCe }); progressDialog.setOnCancelListener(dialog -> { getConnectionsManager().cancelRequest(reqId, true); - if (fragment != null) { - fragment.setVisibleDialog(null); - } + fragment.setVisibleDialog(null); }); fragment.setVisibleDialog(progressDialog); progressDialog.show(); @@ -13362,7 +13602,7 @@ public class MessagesController extends BaseController implements NotificationCe String reason = null; if (chat != null) { reason = getRestrictionReason(chat.restriction_reason); - } else if (user != null) { + } else { reason = getRestrictionReason(user.restriction_reason); if (type != 3 && user.bot) { type = 1; @@ -13439,7 +13679,7 @@ public class MessagesController extends BaseController implements NotificationCe openChatOrProfileWith(res.users.get(0), null, fragment, type, false); } } else { - if (fragment != null && fragment.getParentActivity() != null) { + if (fragment.getParentActivity() != null) { try { Toast.makeText(fragment.getParentActivity(), LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); } catch (Exception e) { @@ -13480,7 +13720,7 @@ public class MessagesController extends BaseController implements NotificationCe ArrayList messArr = (ArrayList) args[2]; boolean isCache = (Boolean) args[3]; if (messArr.isEmpty() && isCache) { - loadMessages(dialog_id, 0, false, 20, 3, 0, false, 0, classGuid, 3, 0, false, false, 0, 0, 0); + loadMessages(dialog_id, 0, false, 20, 3, 0, false, 0, classGuid, 3, 0, false, 0, 0, 0, 0); } else { getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.loadingMessagesFailed); @@ -13501,6 +13741,6 @@ public class MessagesController extends BaseController implements NotificationCe getNotificationCenter().addObserver(delegate, NotificationCenter.loadingMessagesFailed); } - loadMessages(dialog_id, 0, false, 1, finalMessageId, 0, true, 0, classGuid, 3, 0, false, false, 0, 0, 0); + loadMessages(dialog_id, 0, false, 1, finalMessageId, 0, true, 0, classGuid, 3, 0, false, 0, 0, 0, 0); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index 35b43db2d..4cba8a63a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -90,7 +90,7 @@ public class MessagesStorage extends BaseController { private CountDownLatch openSync = new CountDownLatch(1); private static volatile MessagesStorage[] Instance = new MessagesStorage[UserConfig.MAX_ACCOUNT_COUNT]; - private final static int LAST_DB_VERSION = 70; + private final static int LAST_DB_VERSION = 73; public static MessagesStorage getInstance(int num) { MessagesStorage localInstance = Instance[num]; @@ -341,8 +341,8 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE user_settings(uid INTEGER PRIMARY KEY, info BLOB, pinned INTEGER)").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS user_settings_pinned_idx ON user_settings(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); - database.executeFast("CREATE TABLE chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + database.executeFast("CREATE TABLE chat_pinned_v2(uid INTEGER, mid INTEGER, data BLOB, PRIMARY KEY (uid, mid));").stepThis().dispose(); + database.executeFast("CREATE TABLE chat_pinned_count(uid INTEGER PRIMARY KEY, count INTEGER, end INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE chat_hints(did INTEGER, type INTEGER, rating REAL, date INTEGER, PRIMARY KEY(did, type))").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS chat_hints_rating_idx ON chat_hints(rating);").stepThis().dispose(); @@ -372,7 +372,7 @@ public class MessagesStorage extends BaseController { database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); database.executeFast("CREATE TABLE pending_tasks(id INTEGER PRIMARY KEY, data BLOB);").stepThis().dispose(); database.executeFast("CREATE TABLE requested_holes(uid INTEGER, seq_out_start INTEGER, seq_out_end INTEGER, PRIMARY KEY (uid, seq_out_start, seq_out_end));").stepThis().dispose(); - database.executeFast("CREATE TABLE sharing_locations(uid INTEGER PRIMARY KEY, mid INTEGER, date INTEGER, period INTEGER, message BLOB);").stepThis().dispose(); + database.executeFast("CREATE TABLE sharing_locations(uid INTEGER PRIMARY KEY, mid INTEGER, date INTEGER, period INTEGER, message BLOB, proximity INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE emoji_keywords_v2(lang TEXT, keyword TEXT, emoji TEXT, PRIMARY KEY(lang, keyword, emoji));").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS emoji_keywords_v2_keyword ON emoji_keywords_v2(keyword);").stepThis().dispose(); @@ -390,9 +390,6 @@ public class MessagesStorage extends BaseController { //version database.executeFast("PRAGMA user_version = " + LAST_DB_VERSION).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(); } else { int version = database.executeInt("PRAGMA user_version"); if (BuildVars.LOGS_ENABLED) { @@ -694,8 +691,6 @@ public class MessagesStorage extends BaseController { if (version == 30) { database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); - database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); - database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose(); database.executeFast("PRAGMA user_version = 31").stepThis().dispose(); version = 31; @@ -800,7 +795,6 @@ public class MessagesStorage extends BaseController { version = 49; } if (version == 49) { - database.executeFast("DELETE FROM chat_pinned WHERE uid = 1").stepThis().dispose(); database.executeFast("CREATE TABLE IF NOT EXISTS user_settings(uid INTEGER PRIMARY KEY, info BLOB, pinned INTEGER)").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS user_settings_pinned_idx ON user_settings(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); database.executeFast("PRAGMA user_version = 50").stepThis().dispose(); @@ -907,18 +901,33 @@ public class MessagesStorage extends BaseController { version = 68; } if (version == 68) { - database.executeFast("ALTER TABLE messages ADD COLUMN forwards INTEGER default 0").stepThis().dispose(); + executeNoException("ALTER TABLE messages ADD COLUMN forwards INTEGER default 0"); database.executeFast("PRAGMA user_version = 69").stepThis().dispose(); version = 69; } if (version == 69) { - database.executeFast("ALTER TABLE messages ADD COLUMN replies_data BLOB default NULL").stepThis().dispose(); - database.executeFast("ALTER TABLE messages ADD COLUMN thread_reply_id INTEGER default 0").stepThis().dispose(); + executeNoException("ALTER TABLE messages ADD COLUMN replies_data BLOB default NULL"); + executeNoException("ALTER TABLE messages ADD COLUMN thread_reply_id INTEGER default 0"); database.executeFast("CREATE INDEX IF NOT EXISTS uid_thread_reply_id_mid_idx_messages ON messages(uid, thread_reply_id, mid) WHERE thread_reply_id != 0;").stepThis().dispose(); database.executeFast("PRAGMA user_version = 70").stepThis().dispose(); version = 70; } if (version == 70) { + database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned_v2(uid INTEGER, mid INTEGER, data BLOB, PRIMARY KEY (uid, mid));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 71").stepThis().dispose(); + version = 71; + } + if (version == 71) { + executeNoException("ALTER TABLE sharing_locations ADD COLUMN proximity INTEGER default 0"); + database.executeFast("PRAGMA user_version = 72").stepThis().dispose(); + version = 72; + } + if (version == 72) { + database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned_count(uid INTEGER PRIMARY KEY, count INTEGER, end INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 73").stepThis().dispose(); + version = 73; + } + if (version == 73) { } } catch (Exception e) { @@ -927,6 +936,14 @@ public class MessagesStorage extends BaseController { }); } + private void executeNoException(String query) { + try { + database.executeFast(query).stepThis().dispose(); + } catch (Exception e) { + FileLog.e(e); + } + } + private void cleanupInternal(boolean deleteFiles) { lastDateValue = 0; lastSeqValue = 0; @@ -2928,6 +2945,7 @@ public class MessagesStorage extends BaseController { final ArrayList mids = new ArrayList<>(); SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); try { while (cursor.next()) { @@ -2938,7 +2956,7 @@ public class MessagesStorage extends BaseController { message.readAttachPath(data, getUserConfig().clientUserId); if (UserObject.isReplyUser(did) && MessageObject.getPeerId(message.fwd_from.from_id) == fromId || MessageObject.getFromChatId(message) == fromId && message.id != 1) { mids.add(message.id); - addFilesToDelete(message, filesToDelete, idsToDelete, false); + addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); } } data.reuse(); @@ -2949,7 +2967,10 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); deleteFromDownloadQueue(idsToDelete, true); - AndroidUtilities.runOnUIThread(() -> getMessagesController().markDialogMessageAsDeleted(mids, did)); + AndroidUtilities.runOnUIThread(() -> { + getFileLoader().cancelLoadFiles(namesToDelete); + getMessagesController().markDialogMessageAsDeleted(mids, did); + }); markMessagesAsDeletedInternal(mids, channelId, false, false); updateDialogsWithDeletedMessagesInternal(mids, null, channelId); getFileLoader().deleteFiles(filesToDelete, 0); @@ -2962,7 +2983,7 @@ public class MessagesStorage extends BaseController { }); } - private boolean addFilesToDelete(TLRPC.Message message, ArrayList filesToDelete, ArrayList> ids, boolean forceCache) { + private boolean addFilesToDelete(TLRPC.Message message, ArrayList filesToDelete, ArrayList> ids, ArrayList namesToDelete, boolean forceCache) { if (message == null) { return false; } @@ -2995,21 +3016,29 @@ public class MessagesStorage extends BaseController { if (photo != null) { for (int a = 0, N = photo.sizes.size(); a < N; a++) { TLRPC.PhotoSize photoSize = photo.sizes.get(a); + String name = FileLoader.getAttachFileName(photoSize); + if (!TextUtils.isEmpty(name)) { + namesToDelete.add(name); + } File file = FileLoader.getPathToAttach(photoSize); - if (file != null && file.toString().length() > 0) { + if (file.toString().length() > 0) { filesToDelete.add(file); } } return true; } else if (document != null) { + String name = FileLoader.getAttachFileName(document); + if (!TextUtils.isEmpty(name)) { + namesToDelete.add(name); + } File file = FileLoader.getPathToAttach(document, forceCache); - if (file != null && file.toString().length() > 0) { + if (file.toString().length() > 0) { filesToDelete.add(file); } for (int a = 0, N = document.thumbs.size(); a < N; a++) { TLRPC.PhotoSize photoSize = document.thumbs.get(a); file = FileLoader.getPathToAttach(photoSize); - if (file != null && file.toString().length() > 0) { + if (file.toString().length() > 0) { filesToDelete.add(file); } } @@ -3035,6 +3064,7 @@ public class MessagesStorage extends BaseController { if ((int) did == 0 || messagesOnly == 2) { SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); try { while (cursor.next()) { @@ -3043,7 +3073,7 @@ public class MessagesStorage extends BaseController { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); - addFilesToDelete(message, filesToDelete, idsToDelete, false); + addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); } } } catch (Exception e) { @@ -3051,13 +3081,15 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); deleteFromDownloadQueue(idsToDelete, true); + AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, messagesOnly); } if (messagesOnly == 0 || messagesOnly == 3) { database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose(); database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose(); - database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned_count WHERE uid = " + did).stepThis().dispose(); database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose(); int lower_id = (int) did; @@ -3244,6 +3276,8 @@ public class MessagesStorage extends BaseController { String ids = "(" + TextUtils.join(",", dids) + ")"; database.beginTransaction(); + database.executeFast("DELETE FROM chat_pinned_count WHERE uid IN " + ids).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned_v2 WHERE uid IN " + ids).stepThis().dispose(); database.executeFast("DELETE FROM dialogs WHERE did IN " + ids).stepThis().dispose(); database.executeFast("DELETE FROM messages WHERE uid IN " + ids).stepThis().dispose(); database.executeFast("DELETE FROM polls WHERE 1").stepThis().dispose(); @@ -3387,6 +3421,7 @@ public class MessagesStorage extends BaseController { storageQueue.postRunnable(() -> { try { ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); final ArrayList messages = new ArrayList<>(); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); @@ -3397,7 +3432,7 @@ public class MessagesStorage extends BaseController { message.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); if (message.media != null) { - if (!addFilesToDelete(message, filesToDelete, idsToDelete, true)) { + if (!addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, true)) { continue; } else { if (message.media.document != null) { @@ -3474,6 +3509,7 @@ public class MessagesStorage extends BaseController { } }); } + AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, 0); } catch (Exception e) { FileLog.e(e); @@ -4293,7 +4329,7 @@ public class MessagesStorage extends BaseController { continue; } } - if (mutedDialogs.indexOfKey(did) >= 0 && filter.alwaysShow.indexOf(did) >= 0) { + if (mutedDialogs.indexOfKey(did) >= 0 && filter.alwaysShow.contains(did)) { unreadCount--; } } @@ -4600,7 +4636,7 @@ public class MessagesStorage extends BaseController { if (info instanceof TLRPC.TL_chatFull) { info.participants = participants; final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, finalInfo, 0, false, null)); + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, finalInfo, 0, false)); SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?, ?)"); NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); @@ -4657,10 +4693,10 @@ public class MessagesStorage extends BaseController { }); } - public void updateChannelUsers(final int channel_id, final ArrayList participants) { + public void updateChannelUsers(final int channelId, final ArrayList participants) { storageQueue.postRunnable(() -> { try { - long did = -channel_id; + long did = -channelId; database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); database.beginTransaction(); SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_users_v2 VALUES(?, ?, ?, ?)"); @@ -4681,7 +4717,7 @@ public class MessagesStorage extends BaseController { } state.dispose(); database.commitTransaction(); - loadChatInfo(channel_id, null, false, true); + loadChatInfo(channelId, true, null, false, true); } catch (Exception e) { FileLog.e(e); } @@ -4750,12 +4786,16 @@ public class MessagesStorage extends BaseController { }); } - public void loadUserInfo(TLRPC.User user, final boolean force, int classGuid) { + public void loadUserInfo(TLRPC.User user, final boolean force, int classGuid, int fromMessageId) { if (user == null) { return; } storageQueue.postRunnable(() -> { - MessageObject pinnedMessageObject = null; + HashMap pinnedMessagesMap = new HashMap<>(); + ArrayList pinnedMessages = new ArrayList<>(); + int totalPinnedCount = 0; + boolean pinnedEndReached = false; + TLRPC.UserFull info = null; try { SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM user_settings WHERE uid = " + user.id); @@ -4763,18 +4803,47 @@ public class MessagesStorage extends BaseController { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { info = TLRPC.UserFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); info.pinned_msg_id = cursor.intValue(1); + data.reuse(); } } cursor.dispose(); + + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT mid FROM chat_pinned_v2 WHERE uid = %d ORDER BY mid DESC", user.id)); + while (cursor.next()) { + int id = cursor.intValue(0); + pinnedMessages.add(id); + pinnedMessagesMap.put(id, null); + } + cursor.dispose(); + + cursor = database.queryFinalized("SELECT count, end FROM chat_pinned_count WHERE uid = " + user.id); + if (cursor.next()) { + totalPinnedCount = cursor.intValue(0); + pinnedEndReached = cursor.intValue(1) != 0; + } + cursor.dispose(); + if (info != null && info.pinned_msg_id != 0) { - pinnedMessageObject = getMediaDataController().loadPinnedMessage(user.id, 0, info.pinned_msg_id, false); + if (pinnedMessages.isEmpty() || info.pinned_msg_id > pinnedMessages.get(0)) { + pinnedMessages.clear(); + pinnedMessages.add(info.pinned_msg_id); + pinnedMessagesMap.put(info.pinned_msg_id, null); + } + } + if (!pinnedMessages.isEmpty()) { + ArrayList messageObjects = getMediaDataController().loadPinnedMessages(user.id, 0, pinnedMessages, false); + if (messageObjects != null) { + for (int a = 0, N = messageObjects.size(); a < N; a++) { + MessageObject messageObject = messageObjects.get(a); + pinnedMessagesMap.put(messageObject.getId(), messageObject); + } + } } } catch (Exception e) { FileLog.e(e); } finally { - getMessagesController().processUserInfo(user, info, true, force, pinnedMessageObject, classGuid); + getMessagesController().processUserInfo(user, info, true, force, classGuid, pinnedMessages, pinnedMessagesMap, totalPinnedCount, pinnedEndReached); } }); } @@ -4873,43 +4942,6 @@ public class MessagesStorage extends BaseController { }); } - public void updateUserPinnedMessage(final int userId, final int messageId) { - storageQueue.postRunnable(() -> { - try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM user_settings WHERE uid = " + userId); - TLRPC.UserFull info = null; - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.UserFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); - } - } - cursor.dispose(); - if (info instanceof TLRPC.UserFull) { - info.pinned_msg_id = messageId; - info.flags |= 64; - - final TLRPC.UserFull finalInfo = info; - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.userInfoDidLoad, userId, finalInfo, null)); - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_settings VALUES(?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); - info.serializeToStream(data); - state.bindInteger(1, userId); - state.bindByteBuffer(2, data); - state.bindInteger(3, info.pinned_msg_id); - state.step(); - state.dispose(); - data.reuse(); - } - } catch (Exception e) { - FileLog.e(e); - } - }); - } - public void updateChatOnlineCount(final int channelId, final int onlineCount) { storageQueue.postRunnable(() -> { try { @@ -4925,43 +4957,123 @@ public class MessagesStorage extends BaseController { }); } - public void updateChatPinnedMessage(final int channelId, final int messageId) { + public void updatePinnedMessages(long dialogId, ArrayList ids, boolean pin, int totalCount, int maxId, boolean end, HashMap messages) { storageQueue.postRunnable(() -> { try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned, online FROM chat_settings_v2 WHERE uid = " + channelId); - TLRPC.ChatFull info = null; - if (cursor.next()) { - NativeByteBuffer data = cursor.byteBufferValue(0); - if (data != null) { - info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); - data.reuse(); - info.pinned_msg_id = cursor.intValue(1); - info.online_count = cursor.intValue(2); + if (pin) { + database.beginTransaction(); + int alreadyAdded = 0; + boolean endReached; + if (messages != null) { + if (maxId == 0) { + database.executeFast("DELETE FROM chat_pinned_v2 WHERE uid = " + dialogId).stepThis().dispose(); + } + } else { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM chat_pinned_v2 WHERE uid = %d AND mid IN (%s)", dialogId, TextUtils.join(",", ids))); + alreadyAdded = cursor.next() ? cursor.intValue(0) : 0; } - } - cursor.dispose(); - if (info != null) { - if (info instanceof TLRPC.TL_channelFull) { - info.pinned_msg_id = messageId; - info.flags |= 32; - } else if (info instanceof TLRPC.TL_chatFull) { - info.pinned_msg_id = messageId; - info.flags |= 64; + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_pinned_v2 VALUES(?, ?, ?)"); + for (int a = 0, N = ids.size(); a < N; a++) { + Integer id = ids.get(a); + state.requery(); + state.bindLong(1, dialogId); + state.bindInteger(2, id); + MessageObject message = null; + if (messages != null) { + message = messages.get(id); + } + NativeByteBuffer data = null; + if (message != null) { + data = new NativeByteBuffer(message.messageOwner.getObjectSize()); + message.messageOwner.serializeToStream(data); + state.bindByteBuffer(3, data); + } else { + state.bindNull(3); + } + state.step(); + if (data != null) { + data.reuse(); + } + } + state.dispose(); + database.commitTransaction(); + + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM chat_pinned_v2 WHERE uid = %d", dialogId)); + int newCount1 = cursor.next() ? cursor.intValue(0) : 0; + cursor.dispose(); + + int newCount; + if (messages != null) { + newCount = Math.max(totalCount, newCount1); + endReached = end; + } else { + SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT count, end FROM chat_pinned_count WHERE uid = %d", dialogId)); + int newCount2; + if (cursor2.next()) { + newCount2 = cursor2.intValue(0); + endReached = cursor2.intValue(1) != 0; + } else { + newCount2 = 0; + endReached = false; + } + cursor2.dispose(); + newCount = Math.max(newCount2 + (ids.size() - alreadyAdded), newCount1); } - final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, finalInfo, 0, false, null)); - - SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?, ?)"); - NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); - info.serializeToStream(data); - state.bindInteger(1, channelId); - state.bindByteBuffer(2, data); - state.bindInteger(3, info.pinned_msg_id); - state.bindInteger(4, info.online_count); + state = database.executeFast("REPLACE INTO chat_pinned_count VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, dialogId); + state.bindInteger(2, newCount); + state.bindInteger(3, endReached ? 1 : 0); state.step(); state.dispose(); - data.reuse(); + + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialogId, ids, true, null, messages, maxId, newCount, endReached)); + } else { + int newCount; + boolean endReached; + if (ids == null) { + database.executeFast("DELETE FROM chat_pinned_v2 WHERE uid = " + dialogId).stepThis().dispose(); + if (dialogId < 0) { + database.executeFast("UPDATE chat_settings_v2 SET pinned = " + 0 + " WHERE uid = " + dialogId).stepThis().dispose(); + } else { + database.executeFast("UPDATE user_settings SET pinned = " + 0 + " WHERE uid = " + dialogId).stepThis().dispose(); + } + newCount = 0; + endReached = true; + } else { + database.executeFast(String.format("DELETE FROM chat_pinned_v2 WHERE uid = " + dialogId + " AND mid IN(%s)", TextUtils.join(",", ids))).stepThis().dispose(); + + SQLiteCursor cursor = database.queryFinalized("SELECT changes()"); + int updatedCount = cursor.next() ? cursor.intValue(0) : 0; + cursor.dispose(); + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM chat_pinned_v2 WHERE uid = %d", dialogId)); + int newCount1 = cursor.next() ? cursor.intValue(0) : 0; + cursor.dispose(); + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT count, end FROM chat_pinned_count WHERE uid = %d", dialogId)); + int newCount2; + if (cursor.next()) { + newCount2 = Math.max(0, cursor.intValue(0) - updatedCount); + endReached = cursor.intValue(1) != 0; + } else { + newCount2 = 0; + endReached = false; + } + cursor.dispose(); + newCount = Math.max(newCount1, newCount2); + } + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_pinned_count VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, dialogId); + state.bindInteger(2, newCount); + state.bindInteger(3, endReached ? 1 : 0); + state.step(); + state.dispose(); + + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialogId, ids, false, null, messages, maxId, newCount, endReached)); } } catch (Exception e) { FileLog.e(e); @@ -5026,7 +5138,7 @@ public class MessagesStorage extends BaseController { info.participants.version = version; final TLRPC.ChatFull finalInfo = info; - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, finalInfo, 0, false, null)); + AndroidUtilities.runOnUIThread(() -> getNotificationCenter().postNotificationName(NotificationCenter.chatInfoDidLoad, finalInfo, 0, false)); SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?, ?)"); NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); @@ -5081,12 +5193,17 @@ public class MessagesStorage extends BaseController { return result[0]; } - private TLRPC.ChatFull loadChatInfoInternal(final int chat_id, final boolean force, final boolean byChannelUsers) { - MessageObject pinnedMessageObject = null; + private TLRPC.ChatFull loadChatInfoInternal(final int chatId, boolean isChannel, final boolean force, final boolean byChannelUsers, int fromMessageId) { TLRPC.ChatFull info = null; ArrayList loadedUsers = new ArrayList<>(); + + HashMap pinnedMessagesMap = new HashMap<>(); + ArrayList pinnedMessages = new ArrayList<>(); + int totalPinnedCount = 0; + boolean pinnedEndReached = false; + try { - SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned, online FROM chat_settings_v2 WHERE uid = " + chat_id); + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned, online FROM chat_settings_v2 WHERE uid = " + chatId); if (cursor.next()) { NativeByteBuffer data = cursor.byteBufferValue(0); if (data != null) { @@ -5111,7 +5228,7 @@ public class MessagesStorage extends BaseController { getUsersInternal(usersToLoad.toString(), loadedUsers); } } else if (info instanceof TLRPC.TL_channelFull) { - cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chat_id) + " ORDER BY cu.date DESC"); + cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chatId) + " ORDER BY cu.date DESC"); info.participants = new TLRPC.TL_chatParticipants(); while (cursor.next()) { try { @@ -5157,21 +5274,54 @@ public class MessagesStorage extends BaseController { getUsersInternal(usersToLoad.toString(), loadedUsers); } } + + cursor = getMessagesStorage().getDatabase().queryFinalized(String.format(Locale.US, "SELECT mid FROM chat_pinned_v2 WHERE uid = %d ORDER BY mid DESC", -chatId)); + while (cursor.next()) { + int id = cursor.intValue(0); + pinnedMessages.add(id); + pinnedMessagesMap.put(id, null); + } + cursor.dispose(); + + cursor = database.queryFinalized("SELECT count, end FROM chat_pinned_count WHERE uid = " + (-chatId)); + if (cursor.next()) { + totalPinnedCount = cursor.intValue(0); + pinnedEndReached = cursor.intValue(1) != 0; + } + cursor.dispose(); + if (info != null && info.pinned_msg_id != 0) { - pinnedMessageObject = getMediaDataController().loadPinnedMessage(-chat_id, info instanceof TLRPC.TL_channelFull ? chat_id : 0, info.pinned_msg_id, false); + if (pinnedMessages.isEmpty() || info.pinned_msg_id > pinnedMessages.get(0)) { + pinnedMessages.clear(); + pinnedMessages.add(info.pinned_msg_id); + pinnedMessagesMap.put(info.pinned_msg_id, null); + } + } + if (!pinnedMessages.isEmpty()) { + ArrayList messageObjects = getMediaDataController().loadPinnedMessages(-chatId, isChannel ? chatId : 0, pinnedMessages, false); + if (messageObjects != null) { + for (int a = 0, N = messageObjects.size(); a < N; a++) { + MessageObject messageObject = messageObjects.get(a); + pinnedMessagesMap.put(messageObject.getId(), messageObject); + } + } } } catch (Exception e) { FileLog.e(e); } finally { - getMessagesController().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject); + getMessagesController().processChatInfo(chatId, info, loadedUsers, true, force, byChannelUsers, pinnedMessages, pinnedMessagesMap, totalPinnedCount, pinnedEndReached); } return info; } - public TLRPC.ChatFull loadChatInfo(final int chat_id, final CountDownLatch countDownLatch, final boolean force, final boolean byChannelUsers) { + public TLRPC.ChatFull loadChatInfo(int chatId, boolean isChannel, CountDownLatch countDownLatch, boolean force, boolean byChannelUsers) { + return loadChatInfo(chatId, isChannel, countDownLatch, force, byChannelUsers, 0); + } + + public TLRPC.ChatFull loadChatInfo(int chatId, boolean isChannel, CountDownLatch countDownLatch, boolean force, boolean byChannelUsers, int fromMessageId) { TLRPC.ChatFull[] result = new TLRPC.ChatFull[1]; storageQueue.postRunnable(() -> { - result[0] = loadChatInfoInternal(chat_id, force, byChannelUsers); + result[0] = loadChatInfoInternal(chatId, isChannel, force, byChannelUsers, fromMessageId); if (countDownLatch != null) { countDownLatch.countDown(); } @@ -6541,7 +6691,7 @@ public class MessagesStorage extends BaseController { runnable.run(); }; } else {*/ - return () -> getMessagesController().processLoadedMessages(res, dialogId, mergeDialogId, countQueryFinal, maxIdOverrideFinal, offset_date, true, classGuid, minUnreadIdFinal, lastMessageIdFinal, countUnreadFinal, maxUnreadDateFinal, load_type, isChannel, isEndFinal, scheduled, replyMessageId, loadIndex, queryFromServerFinal, mentionsUnreadFinal); + return () -> getMessagesController().processLoadedMessages(res, dialogId, mergeDialogId, countQueryFinal, maxIdOverrideFinal, offset_date, true, classGuid, minUnreadIdFinal, lastMessageIdFinal, countUnreadFinal, maxUnreadDateFinal, load_type, isChannel, isEndFinal, scheduled ? 1 : 0, replyMessageId, loadIndex, queryFromServerFinal, mentionsUnreadFinal); //} } @@ -6549,14 +6699,14 @@ public class MessagesStorage extends BaseController { storageQueue.postRunnable(() -> { long mergeDialogIdFinal = mergeDialogId; int lowerId = (int) dialogId; - if (loadInfo) { + /*if (loadInfo) { if (lowerId < 0) { - TLRPC.ChatFull info = loadChatInfoInternal(-lowerId, true, false); + TLRPC.ChatFull info = loadChatInfoInternal(-lowerId, true, false, 0); if (info != null) { mergeDialogIdFinal = -info.migrated_from_chat_id; } } - } + }*/ Utilities.stageQueue.postRunnable(getMessagesInternal(dialogId, mergeDialogIdFinal, count, max_id, offset_date, minDate, classGuid, load_type, isChannel, scheduled, replyMessageId, loadIndex)); }); } @@ -7298,7 +7448,7 @@ public class MessagesStorage extends BaseController { Pair pair = ids.get(a); state.requery(); state.bindLong(1, pair.first); - state.bindInteger(1, pair.second); + state.bindInteger(2, pair.second); state.step(); } state.dispose(); @@ -7474,7 +7624,8 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); - + database.executeFast("DELETE FROM chat_pinned_count WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned_v2 WHERE uid = " + did).stepThis().dispose(); database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); database.executeFast("UPDATE media_counts_v2 SET old = 1 WHERE uid = " + did).stepThis().dispose(); @@ -7664,9 +7815,7 @@ public class MessagesStorage extends BaseController { public void updateRepliesMaxReadId(int chatId, int mid, int readMaxId, boolean useQueue) { if (useQueue) { - storageQueue.postRunnable(() -> { - updateRepliesMaxReadIdInternal(chatId, mid, readMaxId); - }); + storageQueue.postRunnable(() -> updateRepliesMaxReadIdInternal(chatId, mid, readMaxId)); } else { updateRepliesMaxReadIdInternal(chatId, mid, readMaxId); } @@ -8774,6 +8923,7 @@ public class MessagesStorage extends BaseController { String ids; final ArrayList temp = new ArrayList<>(messages); LongSparseArray dialogsToUpdate = new LongSparseArray<>(); + LongSparseArray> messagesByDialogs = new LongSparseArray<>(); if (channelId != 0) { StringBuilder builder = new StringBuilder(messages.size()); for (int a = 0; a < messages.size(); a++) { @@ -8789,6 +8939,7 @@ public class MessagesStorage extends BaseController { ids = TextUtils.join(",", messages); } ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); int currentUser = getUserConfig().getClientUserId(); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data, read_state, out, mention, mid FROM messages WHERE mid IN(%s)", ids)); @@ -8798,6 +8949,12 @@ public class MessagesStorage extends BaseController { long did = cursor.longValue(0); int mid = cursor.intValue(5); temp.remove((Integer) mid); + ArrayList mids = messagesByDialogs.get(did); + if (mids == null) { + mids = new ArrayList<>(); + messagesByDialogs.put(did, mids); + } + mids.add(mid); if (did != currentUser) { int read_state = cursor.intValue(2); if (cursor.intValue(3) == 0) { @@ -8822,7 +8979,7 @@ public class MessagesStorage extends BaseController { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); - addFilesToDelete(message, filesToDelete, idsToDelete, false); + addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); } } } catch (Exception e) { @@ -8830,6 +8987,7 @@ public class MessagesStorage extends BaseController { } cursor.dispose(); deleteFromDownloadQueue(idsToDelete, true); + AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, 0); for (int a = 0; a < dialogsToUpdate.size(); a++) { @@ -8855,6 +9013,30 @@ public class MessagesStorage extends BaseController { state.dispose(); } + for (int a = 0, N = messagesByDialogs.size(); a < N; a++) { + long did = messagesByDialogs.keyAt(a); + ArrayList mids = messagesByDialogs.valueAt(a); + database.executeFast(String.format(Locale.US, "DELETE FROM chat_pinned_v2 WHERE uid = %d AND mid IN(%s)", did, TextUtils.join(",", mids))).stepThis().dispose(); + int updatedCount = 0; + cursor = database.queryFinalized("SELECT changes()"); + if (cursor.next()) { + updatedCount = cursor.intValue(0); + } + cursor.dispose(); + if (updatedCount > 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT count FROM chat_pinned_count WHERE uid = %d", did)); + if (cursor.next()) { + int count = cursor.intValue(0); + SQLitePreparedStatement state = database.executeFast("UPDATE chat_pinned_count SET count = ? WHERE uid = ?"); + state.requery(); + state.bindInteger(1, Math.max(0, count - updatedCount)); + state.bindLong(2, did); + state.step(); + state.dispose(); + } + cursor.dispose(); + } + } database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM polls WHERE mid IN(%s)", ids)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM bot_keyboard WHERE mid IN(%s)", ids)).stepThis().dispose(); @@ -8991,11 +9173,11 @@ public class MessagesStorage extends BaseController { NativeByteBuffer data = cursor.byteBufferValue(16); if (data != null) { dialogFolder.folder = TLRPC.TL_folder.TLdeserialize(data, data.readInt32(false), false); + data.reuse(); } else { dialogFolder.folder = new TLRPC.TL_folder(); dialogFolder.folder.id = cursor.intValue(15); } - data.reuse(); } dialog = dialogFolder; } else { @@ -9069,7 +9251,7 @@ public class MessagesStorage extends BaseController { } if (!dialogs.dialogs.isEmpty() || !encryptedChats.isEmpty()) { - getMessagesController().processDialogsUpdate(dialogs, encryptedChats); + getMessagesController().processDialogsUpdate(dialogs, encryptedChats, true); } } catch (Exception e) { FileLog.e(e); @@ -9108,6 +9290,7 @@ public class MessagesStorage extends BaseController { maxMessageId |= ((long) channelId) << 32; ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); int currentUser = getUserConfig().getClientUserId(); @@ -9140,7 +9323,7 @@ public class MessagesStorage extends BaseController { TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); message.readAttachPath(data, getUserConfig().clientUserId); data.reuse(); - addFilesToDelete(message, filesToDelete, idsToDelete, false); + addFilesToDelete(message, filesToDelete, idsToDelete, namesToDelete, false); } } } catch (Exception e) { @@ -9149,6 +9332,7 @@ public class MessagesStorage extends BaseController { cursor.dispose(); deleteFromDownloadQueue(idsToDelete, true); + AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, 0); for (int a = 0; a < dialogsToUpdate.size(); a++) { @@ -9174,6 +9358,27 @@ public class MessagesStorage extends BaseController { state.dispose(); } + database.executeFast(String.format(Locale.US, "DELETE FROM chat_pinned_v2 WHERE uid = %d AND mid <= %d", -channelId, maxMessageId)).stepThis().dispose(); + int updatedCount = 0; + cursor = database.queryFinalized("SELECT changes()"); + if (cursor.next()) { + updatedCount = cursor.intValue(0); + } + cursor.dispose(); + if (updatedCount > 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT count FROM chat_pinned_count WHERE uid = %d", -channelId)); + if (cursor.next()) { + int count = cursor.intValue(0); + SQLitePreparedStatement state = database.executeFast("UPDATE chat_pinned_count SET count = ? WHERE uid = ?"); + state.requery(); + state.bindInteger(1, Math.max(0, count - updatedCount)); + state.bindLong(2, -channelId); + state.step(); + state.dispose(); + } + cursor.dispose(); + } + database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE uid = %d AND mid <= %d", -channelId, maxMessageId)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "DELETE FROM media_v2 WHERE uid = %d AND mid <= %d", -channelId, maxMessageId)).stepThis().dispose(); database.executeFast(String.format(Locale.US, "UPDATE media_counts_v2 SET old = 1 WHERE uid = %d", -channelId)).stepThis().dispose(); @@ -9598,6 +9803,7 @@ public class MessagesStorage extends BaseController { //load_type == 3 ? load around message //load_type == 4 ? load around date ArrayList filesToDelete = new ArrayList<>(); + ArrayList namesToDelete = new ArrayList<>(); ArrayList> idsToDelete = new ArrayList<>(); SQLitePreparedStatement state_messages = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?)"); @@ -9638,7 +9844,7 @@ public class MessagesStorage extends BaseController { sameMedia = oldMessage.media.document.id == message.media.document.id; } if (!sameMedia) { - addFilesToDelete(oldMessage, filesToDelete, idsToDelete, false); + addFilesToDelete(oldMessage, filesToDelete, idsToDelete, namesToDelete, false); } } boolean oldMention = cursor.intValue(3) != 0; @@ -9812,6 +10018,7 @@ public class MessagesStorage extends BaseController { getMediaDataController().putBotKeyboard(dialog_id, botKeyboard); } deleteFromDownloadQueue(idsToDelete, false); + AndroidUtilities.runOnUIThread(() -> getFileLoader().cancelLoadFiles(namesToDelete)); getFileLoader().deleteFiles(filesToDelete, 0); putUsersInternal(messages.users); putChatsInternal(messages.chats); @@ -9859,6 +10066,25 @@ public class MessagesStorage extends BaseController { if (message.action.chat_id != 0 && !chatsToLoad.contains(message.action.chat_id)) { chatsToLoad.add(message.action.chat_id); } + if (message.action instanceof TLRPC.TL_messageActionGeoProximityReached) { + TLRPC.TL_messageActionGeoProximityReached action = (TLRPC.TL_messageActionGeoProximityReached) message.action; + Integer id = MessageObject.getPeerId(action.from_id); + if (id > 0) { + if (!usersToLoad.contains(id)) { + usersToLoad.add(id); + } + } else if (!chatsToLoad.contains(-id)) { + chatsToLoad.add(-id); + } + id = MessageObject.getPeerId(action.to_id); + if (id > 0) { + if (!usersToLoad.contains(id)) { + usersToLoad.add(id); + } + } else if (!chatsToLoad.contains(-id)) { + chatsToLoad.add(-id); + } + } if (!message.action.users.isEmpty()) { for (int a = 0; a < message.action.users.size(); a++) { Integer uid = message.action.users.get(a); @@ -10825,6 +11051,9 @@ public class MessagesStorage extends BaseController { try { String savedMessages = LocaleController.getString("SavedMessages", R.string.SavedMessages).toLowerCase(); String search1 = query.trim().toLowerCase(); + if (TextUtils.isEmpty(search1)) { + return; + } String search2 = LocaleController.getInstance().getTranslitString(search1); if (search1.equals(search2) || search2.length() == 0) { search2 = null; @@ -10841,7 +11070,7 @@ public class MessagesStorage extends BaseController { int resultCount = 0; LongSparseArray dialogsResult = new LongSparseArray<>(); - SQLiteCursor cursor = null; + SQLiteCursor cursor; if (folderId >= 0) { cursor = getDatabase().queryFinalized("SELECT did, date FROM dialogs WHERE folder_id = ? ORDER BY date DESC LIMIT 600", folderId); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java index 51cb5ba85..6845e0541 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -18,7 +18,7 @@ import tw.nekomimi.nekogram.utils.FileUtil; public class NativeLoader { - private final static int LIB_VERSION = 33; + private final static int LIB_VERSION = 34; 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 f5359bdf1..392bfe380 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -13,6 +13,7 @@ import android.util.SparseArray; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; public class NotificationCenter { @@ -63,7 +64,7 @@ public class NotificationCenter { public static final int didSetOrRemoveTwoStepPassword = totalEvents++; public static final int didRemoveTwoStepPassword = totalEvents++; public static final int replyMessagesDidLoad = totalEvents++; - public static final int pinnedMessageDidLoad = totalEvents++; + public static final int didLoadPinnedMessages = totalEvents++; public static final int newSessionReceived = totalEvents++; public static final int didReceivedWebpages = totalEvents++; public static final int didReceivedWebpagesInUpdates = totalEvents++; @@ -74,6 +75,7 @@ public class NotificationCenter { public static final int messagesReadContent = totalEvents++; public static final int botInfoDidLoad = totalEvents++; public static final int userInfoDidLoad = totalEvents++; + public static final int pinnedInfoDidLoad = totalEvents++; public static final int botKeyboardDidLoad = totalEvents++; public static final int chatSearchResultsAvailable = totalEvents++; public static final int chatSearchResultsLoading = totalEvents++; @@ -205,6 +207,8 @@ public class NotificationCenter { private SparseArray> removeAfterBroadcast = new SparseArray<>(); private SparseArray> addAfterBroadcast = new SparseArray<>(); private ArrayList delayedPosts = new ArrayList<>(10); + private ArrayList delayedRunnables = new ArrayList<>(10); + private ArrayList delayedRunnablesTmp = new ArrayList<>(10); private ArrayList delayedPostsTmp = new ArrayList<>(10); private ArrayList postponeCallbackList = new ArrayList<>(10); @@ -213,6 +217,8 @@ public class NotificationCenter { private int animationInProgressCount; private int animationInProgressPointer = 1; + HashSet heavyOperationsCounter = new HashSet<>(); + private final HashMap allowedNotifications = new HashMap<>(); public interface NotificationCenterDelegate { @@ -268,14 +274,21 @@ public class NotificationCenter { } public int setAnimationInProgress(int oldIndex, int[] allowedNotifications) { + return setAnimationInProgress(oldIndex, allowedNotifications, true); + } + + public int setAnimationInProgress(int oldIndex, int[] allowedNotifications, boolean stopHeavyOperations) { onAnimationFinish(oldIndex); - if (animationInProgressCount == 0) { + if (heavyOperationsCounter.isEmpty() && stopHeavyOperations) { NotificationCenter.getGlobalInstance().postNotificationName(stopAllHeavyOperations, 512); } animationInProgressCount++; animationInProgressPointer++; + if (stopHeavyOperations) { + heavyOperationsCounter.add(animationInProgressPointer); + } if (allowedNotifications == null) { allowedNotifications = new int[0]; } @@ -298,8 +311,13 @@ public class NotificationCenter { int[] notifications = allowedNotifications.remove(index); if (notifications != null) { animationInProgressCount--; + if (!heavyOperationsCounter.isEmpty()) { + heavyOperationsCounter.remove(index); + if (heavyOperationsCounter.isEmpty()) { + NotificationCenter.getGlobalInstance().postNotificationName(startAllHeavyOperations, 512); + } + } if (animationInProgressCount == 0) { - NotificationCenter.getGlobalInstance().postNotificationName(startAllHeavyOperations, 512); runDelayedNotifications(); } } @@ -316,6 +334,16 @@ public class NotificationCenter { } delayedPostsTmp.clear(); } + + if (!delayedRunnables.isEmpty()) { + delayedRunnablesTmp.clear(); + delayedRunnablesTmp.addAll(delayedRunnables); + delayedRunnables.clear(); + for (int a = 0; a < delayedRunnablesTmp.size(); a++) { + delayedRunnablesTmp.get(a).run(); + } + delayedRunnablesTmp.clear(); + } } public boolean isAnimationInProgress() { @@ -331,7 +359,7 @@ public class NotificationCenter { if (!allowDuringAnimation && !allowedNotifications.isEmpty()) { int size = allowedNotifications.size(); int allowedCount = 0; - for(Integer key : allowedNotifications.keySet()) { + for (Integer key : allowedNotifications.keySet()) { int[] allowed = allowedNotifications.get(key); if (allowed != null) { for (int a = 0; a < allowed.length; a++) { @@ -348,7 +376,7 @@ public class NotificationCenter { } if (id == startAllHeavyOperations) { Integer flags = (Integer) args[0]; - currentHeavyOperationFlags &=~ flags; + currentHeavyOperationFlags &= ~flags; } else if (id == stopAllHeavyOperations) { Integer flags = (Integer) args[0]; currentHeavyOperationFlags |= flags; @@ -487,4 +515,12 @@ public class NotificationCenter { public interface PostponeNotificationCallback { boolean needPostpone(int id, int currentAccount, Object[] args); } + + public void doOnIdle(Runnable runnable) { + if (isAnimationInProgress()) { + delayedRunnables.add(runnable); + } else { + runnable.run(); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java index 6c1819746..cf4307193 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -1255,12 +1255,13 @@ public class NotificationsController extends BaseController { } return messageObject.messageOwner.message; } + int selfUsedId = getUserConfig().getClientUserId(); if (fromId == 0) { fromId = messageObject.getFromChatId(); if (fromId == 0) { fromId = -chat_id; } - } else if (fromId == getUserConfig().getClientUserId()) { + } else if (fromId == selfUsedId) { fromId = messageObject.getFromChatId(); } @@ -1334,7 +1335,9 @@ public class NotificationsController extends BaseController { if (dialogPreviewEnabled && (chat_id == 0 && fromId != 0 && preferences.getBoolean("EnablePreviewAll", true) || chat_id != 0 && (!isChannel && preferences.getBoolean("EnablePreviewGroup", true) || isChannel && preferences.getBoolean("EnablePreviewChannel", true)))) { if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { userName[0] = null; - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionContactSignUp) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) { + return messageObject.messageText.toString(); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionContactSignUp) { return LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, name); } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { return LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, name); @@ -1358,7 +1361,7 @@ public class NotificationsController extends BaseController { if (messageObject.messageOwner.peer_id.channel_id != 0 && !chat.megagroup) { return LocaleController.formatString("ChannelAddedByNotification", R.string.ChannelAddedByNotification, name, chat.title); } else { - if (singleUserId == getUserConfig().getClientUserId()) { + if (singleUserId == selfUsedId) { return LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, name, chat.title); } else { TLRPC.User u2 = getMessagesController().getUser(singleUserId); @@ -1409,7 +1412,7 @@ public class NotificationsController extends BaseController { } } } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser) { - if (messageObject.messageOwner.action.user_id == getUserConfig().getClientUserId()) { + if (messageObject.messageOwner.action.user_id == selfUsedId) { return LocaleController.formatString("NotificationGroupKickYou", R.string.NotificationGroupKickYou, name, chat.title); } else if (messageObject.messageOwner.action.user_id == fromId) { return LocaleController.formatString("NotificationGroupLeftMember", R.string.NotificationGroupLeftMember, name, chat.title); @@ -1503,7 +1506,7 @@ public class NotificationsController extends BaseController { return LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title); } } - } else { + } else if (chat != null) { if (messageObject.replyMessageObject == null) { return LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title); } else { @@ -1575,6 +1578,78 @@ public class NotificationsController extends BaseController { return LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title); } } + } else { + if (messageObject.replyMessageObject == null) { + return LocaleController.formatString("NotificationActionPinnedNoTextUser", R.string.NotificationActionPinnedNoTextUser, name); + } else { + MessageObject object = messageObject.replyMessageObject; + if (object.isMusic()) { + return LocaleController.formatString("NotificationActionPinnedMusicUser", R.string.NotificationActionPinnedMusicUser, name); + } else if (object.isVideo()) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDCF9 " + object.messageOwner.message; + return LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + return LocaleController.formatString("NotificationActionPinnedVideoUser", R.string.NotificationActionPinnedVideoUser, name); + } + } else if (object.isGif()) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83C\uDFAC " + object.messageOwner.message; + return LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + return LocaleController.formatString("NotificationActionPinnedGifUser", R.string.NotificationActionPinnedGifUser, name); + } + } else if (object.isVoice()) { + return LocaleController.formatString("NotificationActionPinnedVoiceUser", R.string.NotificationActionPinnedVoiceUser, name); + } else if (object.isRoundVideo()) { + return LocaleController.formatString("NotificationActionPinnedRoundUser", R.string.NotificationActionPinnedRoundUser, name); + } else if (object.isSticker() || object.isAnimatedSticker()) { + String emoji = object.getStickerEmoji(); + if (emoji != null) { + return LocaleController.formatString("NotificationActionPinnedStickerEmojiUser", R.string.NotificationActionPinnedStickerEmojiUser, name, emoji); + } else { + return LocaleController.formatString("NotificationActionPinnedStickerUser", R.string.NotificationActionPinnedStickerUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDCCE " + object.messageOwner.message; + return LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + return LocaleController.formatString("NotificationActionPinnedFileUser", R.string.NotificationActionPinnedFileUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || object.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + return LocaleController.formatString("NotificationActionPinnedGeoUser", R.string.NotificationActionPinnedGeoUser, name); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { + return LocaleController.formatString("NotificationActionPinnedGeoLiveUser", R.string.NotificationActionPinnedGeoLiveUser, name); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + TLRPC.TL_messageMediaContact mediaContact = (TLRPC.TL_messageMediaContact) object.messageOwner.media; + return LocaleController.formatString("NotificationActionPinnedContactUser", R.string.NotificationActionPinnedContactUser, name, ContactsController.formatName(mediaContact.first_name, mediaContact.last_name)); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { + TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) object.messageOwner.media; + if (mediaPoll.poll.quiz) { + return LocaleController.formatString("NotificationActionPinnedQuizUser", R.string.NotificationActionPinnedQuizUser, name, mediaPoll.poll.question); + } else { + return LocaleController.formatString("NotificationActionPinnedPollUser", R.string.NotificationActionPinnedPollUser, name, mediaPoll.poll.question); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDDBC " + object.messageOwner.message; + return LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + return LocaleController.formatString("NotificationActionPinnedPhotoUser", R.string.NotificationActionPinnedPhotoUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { + return LocaleController.formatString("NotificationActionPinnedGameUser", R.string.NotificationActionPinnedGameUser, name); + } else if (object.messageText != null && object.messageText.length() > 0) { + CharSequence message = object.messageText; + if (message.length() > 20) { + message = message.subSequence(0, 20) + "..."; + } + return LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + return LocaleController.formatString("NotificationActionPinnedNoTextUser", R.string.NotificationActionPinnedNoTextUser, name); + } + } } } } else { @@ -1749,7 +1824,9 @@ public class NotificationsController extends BaseController { if (chat_id == 0 && from_id != 0) { if (dialogPreviewEnabled && preferences.getBoolean("EnablePreviewAll", true)) { if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionContactSignUp) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) { + msg = messageObject.messageText.toString(); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionContactSignUp) { msg = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, name); } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, name); @@ -2017,7 +2094,7 @@ public class NotificationsController extends BaseController { msg = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title); } } - } else { + } else if (chat != null) { if (messageObject.replyMessageObject == null) { msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title); } else { @@ -2089,6 +2166,78 @@ public class NotificationsController extends BaseController { msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title); } } + } else { + if (messageObject.replyMessageObject == null) { + msg = LocaleController.formatString("NotificationActionPinnedNoTextUser", R.string.NotificationActionPinnedNoTextUser, name); + } else { + MessageObject object = messageObject.replyMessageObject; + if (object.isMusic()) { + msg = LocaleController.formatString("NotificationActionPinnedMusicUser", R.string.NotificationActionPinnedMusicUser, name); + } else if (object.isVideo()) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDCF9 " + object.messageOwner.message; + msg = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + msg = LocaleController.formatString("NotificationActionPinnedVideoUser", R.string.NotificationActionPinnedVideoUser, name); + } + } else if (object.isGif()) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83C\uDFAC " + object.messageOwner.message; + msg = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + msg = LocaleController.formatString("NotificationActionPinnedGifUser", R.string.NotificationActionPinnedGifUser, name); + } + } else if (object.isVoice()) { + msg = LocaleController.formatString("NotificationActionPinnedVoiceUser", R.string.NotificationActionPinnedVoiceUser, name); + } else if (object.isRoundVideo()) { + msg = LocaleController.formatString("NotificationActionPinnedRoundUser", R.string.NotificationActionPinnedRoundUser, name); + } else if (object.isSticker() || object.isAnimatedSticker()) { + String emoji = object.getStickerEmoji(); + if (emoji != null) { + msg = LocaleController.formatString("NotificationActionPinnedStickerEmojiUser", R.string.NotificationActionPinnedStickerEmojiUser, name, emoji); + } else { + msg = LocaleController.formatString("NotificationActionPinnedStickerUser", R.string.NotificationActionPinnedStickerUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDCCE " + object.messageOwner.message; + msg = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + msg = LocaleController.formatString("NotificationActionPinnedFileUser", R.string.NotificationActionPinnedFileUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || object.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + msg = LocaleController.formatString("NotificationActionPinnedGeoUser", R.string.NotificationActionPinnedGeoUser, name); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { + msg = LocaleController.formatString("NotificationActionPinnedGeoLiveUser", R.string.NotificationActionPinnedGeoLiveUser, name); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + TLRPC.TL_messageMediaContact mediaContact = (TLRPC.TL_messageMediaContact) messageObject.messageOwner.media; + msg = LocaleController.formatString("NotificationActionPinnedContactUser", R.string.NotificationActionPinnedContactUser, name, ContactsController.formatName(mediaContact.first_name, mediaContact.last_name)); + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPoll) { + TLRPC.TL_messageMediaPoll mediaPoll = (TLRPC.TL_messageMediaPoll) object.messageOwner.media; + if (mediaPoll.poll.quiz) { + msg = LocaleController.formatString("NotificationActionPinnedQuizUser", R.string.NotificationActionPinnedQuizUser, name, mediaPoll.poll.question); + } else { + msg = LocaleController.formatString("NotificationActionPinnedPollUser", R.string.NotificationActionPinnedPollUser, name, mediaPoll.poll.question); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + if (Build.VERSION.SDK_INT >= 19 && !TextUtils.isEmpty(object.messageOwner.message)) { + String message = "\uD83D\uDDBC " + object.messageOwner.message; + msg = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + msg = LocaleController.formatString("NotificationActionPinnedPhotoUser", R.string.NotificationActionPinnedPhotoUser, name); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { + msg = LocaleController.formatString("NotificationActionPinnedGameUser", R.string.NotificationActionPinnedGameUser, name); + } else if (object.messageText != null && object.messageText.length() > 0) { + CharSequence message = object.messageText; + if (message.length() > 20) { + message = message.subSequence(0, 20) + "..."; + } + msg = LocaleController.formatString("NotificationActionPinnedTextUser", R.string.NotificationActionPinnedTextUser, name, message); + } else { + msg = LocaleController.formatString("NotificationActionPinnedNoTextUser", R.string.NotificationActionPinnedNoTextUser, name); + } + } } } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { msg = messageObject.messageText.toString(); @@ -3845,7 +3994,11 @@ public class NotificationsController extends BaseController { } } if (!unsupportedNotificationShortcut()) { - ShortcutManagerCompat.removeDynamicShortcuts(ApplicationLoader.applicationContext, ids); + try { + ShortcutManagerCompat.removeDynamicShortcuts(ApplicationLoader.applicationContext, ids); + } catch (Exception e) { + FileLog.e(e); + } } for (int a = 0; a < oldIdsWear.size(); a++) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java index 012353e49..79328dfcb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -293,6 +293,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe public TLRPC.EncryptedChat encryptedChat; public VideoEditedInfo videoEditedInfo; public boolean performMediaUpload; +public boolean retriedToSend; public int topMessageId; @@ -371,7 +372,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } else if (request.request instanceof TLRPC.TL_messages_sendMultiMedia) { performSendMessageRequestMulti((TLRPC.TL_messages_sendMultiMedia) request.request, request.msgObjs, request.originalPaths, request.parentObjects, request.delayedMessage, request.scheduled); } else { - performSendMessageRequest(request.request, request.msgObj, request.originalPath, request.delayedMessage, request.parentObject, request.scheduled); + performSendMessageRequest(request.request, request.msgObj, request.originalPath, request.delayedMessage, request.parentObject, null, request.scheduled); } } requests = null; @@ -465,19 +466,19 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (file != null && media != null) { if (message.type == 0) { media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, message, true, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, message, true, null, message.parentObject, null, message.scheduled); } else if (message.type == 1) { if (media.file == null) { media.file = file; if (media.thumb == null && message.photoSize != null && message.photoSize.location != null) { performSendDelayedMessage(message); } else { - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, null, message.scheduled); } } else { media.thumb = file; media.flags |= 4; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, null, message.scheduled); } } else if (message.type == 2) { if (media.file == null) { @@ -485,16 +486,16 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (media.thumb == null && message.photoSize != null && message.photoSize.location != null) { performSendDelayedMessage(message); } else { - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, null, message.scheduled); } } else { media.thumb = file; media.flags |= 4; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, null, message.scheduled); } } else if (message.type == 3) { media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, message.scheduled); + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath, null, message.parentObject, null, message.scheduled); } else if (message.type == 4) { if (media instanceof TLRPC.TL_inputMediaUploadedDocument) { if (media.file == null) { @@ -870,6 +871,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe message.messageObjects.remove(index); message.messages.remove(index); message.originalPaths.remove(index); + message.parentObjects.remove(index); if (message.sendRequest != null) { TLRPC.TL_messages_sendMultiMedia request = (TLRPC.TL_messages_sendMultiMedia) message.sendRequest; request.multi_media.remove(index); @@ -1108,7 +1110,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe arr.add(message); getMessagesStorage().putMessages(arr, false, true, false, 0, false); - performSendMessageRequest(req, newMsgObj, null, null, null, false); + performSendMessageRequest(req, newMsgObj, null, null, null, null, false); } public void sendSticker(TLRPC.Document document, long peer, MessageObject replyToMsg, MessageObject replyToTopMsg, Object parentObject, boolean notify, int scheduleDate) { @@ -1333,8 +1335,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } } if (msgObj.messageOwner.post_author != null) { - newMsg.fwd_from.post_author = msgObj.messageOwner.post_author; - newMsg.fwd_from.flags |= 8; + /*newMsg.fwd_from.post_author = msgObj.messageOwner.post_author; + newMsg.fwd_from.flags |= 8;*/ } else if (!msgObj.isOutOwner() && fromId > 0 && msgObj.messageOwner.post) { TLRPC.User signUser = getMessagesController().getUser(fromId); if (signUser != null) { @@ -1992,32 +1994,32 @@ public class SendMessagesHelper extends BaseController implements NotificationCe reqSend = request; if (type == 1) { - performSendMessageRequest(reqSend, messageObject, null, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, null, delayedMessage, parentObject, params, messageObject.scheduled); } else if (type == 2) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, messageObject, originalPath, null, true, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, originalPath, null, true, delayedMessage, parentObject, params, messageObject.scheduled); } } else if (type == 3) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, params, messageObject.scheduled); } } else if (type == 6) { - performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, params, messageObject.scheduled); } else if (type == 7) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, params, messageObject.scheduled); } } else if (type == 8) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, messageObject.scheduled); + performSendMessageRequest(reqSend, messageObject, originalPath, delayedMessage, parentObject, params, messageObject.scheduled); } } } @@ -3019,15 +3021,6 @@ public class SendMessagesHelper extends BaseController implements NotificationCe newMsg.from_id = newMsg.peer_id; } newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; - newMsgObj = new MessageObject(currentAccount, newMsg, replyToMsg, true, true); - newMsgObj.wasJustSent = true; - newMsgObj.scheduled = scheduleDate != 0; - if (!newMsgObj.isForwarded() && (newMsgObj.type == 3 || videoEditedInfo != null || newMsgObj.type == 2) && !TextUtils.isEmpty(newMsg.attachPath)) { - newMsgObj.attachPathExists = true; - } - if (newMsgObj.videoEditedInfo != null && videoEditedInfo == null) { - videoEditedInfo = newMsgObj.videoEditedInfo; - } long groupId = 0; boolean isFinalGroupMedia = false; @@ -3041,6 +3034,16 @@ public class SendMessagesHelper extends BaseController implements NotificationCe isFinalGroupMedia = params.get("final") != null; } + newMsgObj = new MessageObject(currentAccount, newMsg, replyToMsg, true, true); + newMsgObj.wasJustSent = true; + newMsgObj.scheduled = scheduleDate != 0; + if (!newMsgObj.isForwarded() && (newMsgObj.type == 3 || videoEditedInfo != null || newMsgObj.type == 2) && !TextUtils.isEmpty(newMsg.attachPath)) { + newMsgObj.attachPathExists = true; + } + if (newMsgObj.videoEditedInfo != null && videoEditedInfo == null) { + videoEditedInfo = newMsgObj.videoEditedInfo; + } + if (groupId == 0) { ArrayList objArr = new ArrayList<>(); objArr.add(newMsgObj); @@ -3103,7 +3106,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe reqSend.schedule_date = scheduleDate; reqSend.flags |= 1024; } - performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0); if (retryMessageObject == null) { getMediaDataController().cleanDraft(peer, replyToTopMsg != null ? replyToTopMsg.getId() : 0, false); } @@ -3157,6 +3160,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe inputMedia = new TLRPC.TL_inputMediaGeoLive(); inputMedia.period = location.period; inputMedia.flags |= 2; + if (location.heading != 0) { + inputMedia.heading = location.heading; + inputMedia.flags |= 4; + } + if (location.proximity_notification_radius != 0) { + inputMedia.proximity_notification_radius = location.proximity_notification_radius; + inputMedia.flags |= 8; + } } else { inputMedia = new TLRPC.TL_inputMediaGeoPoint(); } @@ -3287,6 +3298,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (forceNoSoundVideo || !TextUtils.isEmpty(path) && path.toLowerCase().endsWith("mp4") && (params == null || params.containsKey("forceDocument"))) { uploadedMedia.nosound_video = true; } + uploadedMedia.force_file = params != null && params.containsKey("forceDocument"); uploadedMedia.mime_type = document.mime_type; uploadedMedia.attributes = document.attributes; } else { @@ -3308,18 +3320,20 @@ public class SendMessagesHelper extends BaseController implements NotificationCe inputMedia = media; } if (!http && uploadedMedia != null) { - delayedMessage = new DelayedMessage(peer); - delayedMessage.originalPath = originalPath; - delayedMessage.type = 2; - delayedMessage.obj = newMsgObj; + if (delayedMessage == null) { + delayedMessage = new DelayedMessage(peer); + delayedMessage.type = 2; + delayedMessage.obj = newMsgObj; + delayedMessage.originalPath = originalPath; + delayedMessage.parentObject = parentObject; + delayedMessage.scheduled = scheduleDate != 0; + } + delayedMessage.inputUploadMedia = uploadedMedia; + delayedMessage.performMediaUpload = performMediaUpload; if (!document.thumbs.isEmpty()) { delayedMessage.photoSize = document.thumbs.get(0); delayedMessage.locationParent = document; } - delayedMessage.parentObject = parentObject; - delayedMessage.inputUploadMedia = uploadedMedia; - delayedMessage.performMediaUpload = performMediaUpload; - delayedMessage.scheduled = scheduleDate != 0; } } else if (type == 8) { TLRPC.TL_inputMediaUploadedDocument uploadedDocument = new TLRPC.TL_inputMediaUploadedDocument(); @@ -3441,35 +3455,35 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (groupId != 0) { performSendDelayedMessage(delayedMessage); } else if (type == 1) { - performSendMessageRequest(reqSend, newMsgObj, null, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, null, delayedMessage, parentObject, params, scheduleDate != 0); } else if (type == 2) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, originalPath, null, true, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, null, true, delayedMessage, parentObject, params, scheduleDate != 0); } } else if (type == 3) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, params, scheduleDate != 0); } } else if (type == 6) { - performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, params, scheduleDate != 0); } else if (type == 7) { if (performMediaUpload && delayedMessage != null) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, params, scheduleDate != 0); } } else if (type == 8) { if (performMediaUpload) { performSendDelayedMessage(delayedMessage); } else { - performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, params, scheduleDate != 0); } } else if (type == 10 || type == 11) { - performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, originalPath, delayedMessage, parentObject, params, scheduleDate != 0); } } else { TLRPC.TL_decryptedMessage reqSend; @@ -3671,24 +3685,28 @@ public class SendMessagesHelper extends BaseController implements NotificationCe reqSend.media.size = document.size; reqSend.media.mime_type = document.mime_type; - if (document.key == null) { - delayedMessage = new DelayedMessage(peer); - delayedMessage.originalPath = originalPath; - delayedMessage.sendEncryptedRequest = reqSend; - delayedMessage.type = 2; - delayedMessage.obj = newMsgObj; - if (params != null && params.containsKey("parentObject")) { - delayedMessage.parentObject = params.get("parentObject"); - } else { - delayedMessage.parentObject = parentObject; + if (document.key == null || groupId != 0) { + if (delayedMessage == null) { + delayedMessage = new DelayedMessage(peer); + delayedMessage.encryptedChat = encryptedChat; + delayedMessage.type = 2; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.originalPath = originalPath; + delayedMessage.obj = newMsgObj; + if (params != null && params.containsKey("parentObject")) { + delayedMessage.parentObject = params.get("parentObject"); + } else { + delayedMessage.parentObject = parentObject; + } + delayedMessage.performMediaUpload = true; + delayedMessage.scheduled = scheduleDate != 0; } - delayedMessage.encryptedChat = encryptedChat; - delayedMessage.performMediaUpload = true; if (path != null && path.length() > 0 && path.startsWith("http")) { delayedMessage.httpLocation = path; } - delayedMessage.scheduled = scheduleDate != 0; - performSendDelayedMessage(delayedMessage); + if (groupId == 0) { + performSendDelayedMessage(delayedMessage); + } } else { TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); encryptedFile.id = document.id; @@ -3741,7 +3759,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe delayedMessage.performMediaUpload = true; request.messages.add(reqSend); TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); - encryptedFile.id = type == 3 ? 1 : 0; + encryptedFile.id = type == 3 || type == 7 ? 1 : 0; request.files.add(encryptedFile); performSendDelayedMessage(delayedMessage); } @@ -3778,7 +3796,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe reqSend.id.add(retryMessageObject.messageOwner.fwd_from.channel_post); } } - performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0); } else if (type == 9) { TLRPC.TL_messages_sendInlineBotResult reqSend = new TLRPC.TL_messages_sendInlineBotResult(); reqSend.peer = sendToPeer; @@ -3799,7 +3817,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe reqSend.clear_draft = true; getMediaDataController().cleanDraft(peer, replyToTopMsg != null ? replyToTopMsg.getId() : 0, false); } - performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, scheduleDate != 0); + performSendMessageRequest(reqSend, newMsgObj, null, null, parentObject, params, scheduleDate != 0); } } catch (Exception e) { FileLog.e(e); @@ -4044,7 +4062,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe getFileLoader().uploadFile(documentLocation, false, false, ConnectionsManager.FileTypeVideo); } putToUploadingMessages(messageObject); - } else { + } else if (message.photoSize != null) { String location = FileLoader.getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.photoSize.location.volume_id + "_" + message.photoSize.location.local_id + ".jpg"; putToDelayedMessages(location, message); message.extraHashMap.put(location + "_o", documentLocation); @@ -4385,8 +4403,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList arrayList = new ArrayList<>(parentObjects); getFileRefController().requestReference(arrayList, req, msgObjs, originalPaths, arrayList, delayedMessage, scheduled); return; - } else if (delayedMessage != null) { + } else if (delayedMessage != null && !delayedMessage.retriedToSend) { + delayedMessage.retriedToSend = true; AndroidUtilities.runOnUIThread(() -> { + boolean hasEmptyFile = false; for (int a = 0, size = req.multi_media.size(); a < size; a++) { if (delayedMessage.parentObjects.get(a) == null) { continue; @@ -4402,8 +4422,21 @@ public class SendMessagesHelper extends BaseController implements NotificationCe delayedMessage.httpLocation = delayedMessage.httpLocations.get(a); delayedMessage.photoSize = delayedMessage.locations.get(a); delayedMessage.performMediaUpload = true; + if (request.media.file == null || delayedMessage.photoSize != null) { + hasEmptyFile = true; + } performSendDelayedMessage(delayedMessage, a); } + if (!hasEmptyFile) { + for (int i = 0; i < msgObjs.size(); i++) { + TLRPC.Message newMsgObj = msgObjs.get(i).messageOwner; + getMessagesStorage().markMessageAsSendError(newMsgObj, scheduled); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + getNotificationCenter().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + removeFromSendingMessages(newMsgObj.id, scheduled); + } + } }); return; } @@ -4547,8 +4580,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe }, null, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter); } - private void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath, DelayedMessage delayedMessage, Object parentObject, boolean scheduled) { - performSendMessageRequest(req, msgObj, originalPath, null, false, delayedMessage, parentObject, scheduled); + private void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath, DelayedMessage delayedMessage, Object parentObject, HashMap params, boolean scheduled) { + performSendMessageRequest(req, msgObj, originalPath, null, false, delayedMessage, parentObject, params, scheduled); } private DelayedMessage findMaxDelayedMessageForMessageId(int messageId, long dialogId) { @@ -4578,7 +4611,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe return maxDelayedMessage; } - protected void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath, DelayedMessage parentMessage, boolean check, DelayedMessage delayedMessage, Object parentObject, boolean scheduled) { + protected void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath, DelayedMessage parentMessage, boolean check, DelayedMessage delayedMessage, Object parentObject, HashMap params, boolean scheduled) { if (!(req instanceof TLRPC.TL_messages_editMessage)) { if (check) { DelayedMessage maxDelayedMessage = findMaxDelayedMessageForMessageId(msgObj.getId(), msgObj.getDialogId()); @@ -4797,8 +4830,8 @@ public class SendMessagesHelper extends BaseController implements NotificationCe existFlags = 0; } - if (MessageObject.isLiveLocationMessage(newMsgObj)) { - getLocationController().addSharingLocation(newMsgObj.dialog_id, newMsgObj.id, newMsgObj.media.period, newMsgObj); + if (MessageObject.isLiveLocationMessage(newMsgObj) && newMsgObj.via_bot_id == 0 && TextUtils.isEmpty(newMsgObj.via_bot_name)) { + getLocationController().addSharingLocation(newMsgObj); } if (!isSentError) { @@ -4875,7 +4908,9 @@ public class SendMessagesHelper extends BaseController implements NotificationCe TLRPC.PhotoSize strippedOld = null; TLRPC.PhotoSize strippedNew = null; TLObject photoObject = null; - if (newMsgObj.isDice()) { + if (newMsgObj.isLiveLocation() && sentMessage.media instanceof TLRPC.TL_messageMediaGeoLive) { + newMsg.media.period = sentMessage.media.period; + } else if (newMsgObj.isDice()) { TLRPC.TL_messageMediaDice mediaDice = (TLRPC.TL_messageMediaDice) newMsg.media; TLRPC.TL_messageMediaDice mediaDiceNew = (TLRPC.TL_messageMediaDice) sentMessage.media; mediaDice.value = mediaDiceNew.value; @@ -5170,7 +5205,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } } - private static boolean prepareSendingDocumentInternal(AccountInstance accountInstance, String path, String originalPath, Uri uri, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, CharSequence caption, final ArrayList entities, final MessageObject editingMessageObject, boolean forceDocument, boolean notify, int scheduleDate) { + private static boolean prepareSendingDocumentInternal(AccountInstance accountInstance, String path, String originalPath, Uri uri, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, CharSequence caption, final ArrayList entities, final MessageObject editingMessageObject, long[] groupId, boolean isGroupFinal, boolean forceDocument, boolean notify, int scheduleDate, Boolean[] withThumb) { if ((path == null || path.length() == 0) && uri == null) { return false; } @@ -5343,7 +5378,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } else { document.mime_type = "application/octet-stream"; } - if (document.mime_type.equals("image/gif") && (editingMessageObject == null || editingMessageObject.getGroupIdForUse() == 0)) { + if (!forceDocument && document.mime_type.equals("image/gif") && (editingMessageObject == null || editingMessageObject.getGroupIdForUse() == 0)) { try { Bitmap bitmap = ImageLoader.loadBitmap(f.getAbsolutePath(), null, 90, 90, true); if (bitmap != null) { @@ -5398,6 +5433,22 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFinal != null) { params.put("parentObject", parentFinal); } + Boolean prevWithThumb = false; + if (withThumb != null) { + prevWithThumb = withThumb[0]; + withThumb[0] = document.mime_type != null && (document.mime_type.toLowerCase().startsWith("image/") || document.mime_type.toLowerCase().startsWith("video/mp4")) || MessageObject.canPreviewDocument(document); + } + if (groupId != null) { + if (withThumb != null && prevWithThumb != null && prevWithThumb != withThumb[0]) { + finishGroup(accountInstance, groupId[0], scheduleDate); + groupId[0] = Utilities.random.nextLong(); + } + params.put("groupId", "" + groupId[0]); + if (isGroupFinal) { + params.put("final", "1"); + } + } + AndroidUtilities.runOnUIThread(() -> { if (editingMessageObject != null) { accountInstance.getSendMessagesHelper().editMessageMedia(editingMessageObject, null, null, documentFinal, pathFinal, params, false, parentFinal); @@ -5430,13 +5481,27 @@ public class SendMessagesHelper extends BaseController implements NotificationCe @UiThread public static void prepareSendingAudioDocuments(AccountInstance accountInstance, ArrayList messageObjects, String caption, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, MessageObject editingMessageObject, boolean notify, int scheduleDate) { new Thread(() -> { - int size = messageObjects.size(); - for (int a = 0; a < size; a++) { + int count = messageObjects.size(); + long groupId = 0; + int mediaCount = 0; + for (int a = 0; a < count; a++) { final MessageObject messageObject = messageObjects.get(a); String originalPath = messageObject.messageOwner.attachPath; final File f = new File(originalPath); boolean isEncrypted = (int) dialogId == 0; + int enryptedLayer = 0; + if (isEncrypted) { + int high_id = (int) (dialogId >> 32); + TLRPC.EncryptedChat encryptedChat = accountInstance.getMessagesController().getEncryptedChat(high_id); + if (encryptedChat != null) { + enryptedLayer = AndroidUtilities.getPeerLayerVersion(encryptedChat.layer); + } + } + if ((!isEncrypted || enryptedLayer >= 73) && count > 1 && mediaCount % 10 == 0) { + groupId = Utilities.random.nextLong(); + mediaCount = 0; + } if (originalPath != null) { originalPath += "audio" + f.length(); @@ -5474,6 +5539,11 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFinal != null) { params.put("parentObject", parentFinal); } + mediaCount++; + params.put("groupId", "" + groupId); + if (mediaCount == 10 || a == count - 1) { + params.put("final", "1"); + } AndroidUtilities.runOnUIThread(() -> { if (editingMessageObject != null) { accountInstance.getSendMessagesHelper().editMessageMedia(editingMessageObject, null, null, documentFinal, messageObject.messageOwner.attachPath, params, false, parentFinal); @@ -5485,6 +5555,26 @@ public class SendMessagesHelper extends BaseController implements NotificationCe }).start(); } + private static void finishGroup(AccountInstance accountInstance, long groupId, int scheduleDate) { + AndroidUtilities.runOnUIThread(() -> { + SendMessagesHelper instance = accountInstance.getSendMessagesHelper(); + ArrayList arrayList = instance.delayedMessages.get("group_" + groupId); + if (arrayList != null && !arrayList.isEmpty()) { + + DelayedMessage message = arrayList.get(0); + + MessageObject prevMessage = message.messageObjects.get(message.messageObjects.size() - 1); + message.finalGroupMessage = prevMessage.getId(); + prevMessage.messageOwner.params.put("final", "1"); + + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + messagesRes.messages.add(prevMessage.messageOwner); + accountInstance.getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduleDate != 0); + instance.sendReadyToSendGroup(message, true, true); + } + }); + } + @UiThread public static void prepareSendingDocuments(AccountInstance accountInstance, ArrayList paths, ArrayList originalPaths, ArrayList uris, String caption, String mime, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, InputContentInfoCompat inputContent, MessageObject editingMessageObject, boolean notify, int scheduleDate) { if (paths == null && originalPaths == null && uris == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) { @@ -5492,20 +5582,62 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } new Thread(() -> { boolean error = false; + long[] groupId = new long[1]; + int mediaCount = 0; + Boolean[] withThumb = new Boolean[1]; + + boolean isEncrypted = (int) dialogId == 0; + int enryptedLayer = 0; + if (isEncrypted) { + int high_id = (int) (dialogId >> 32); + TLRPC.EncryptedChat encryptedChat = accountInstance.getMessagesController().getEncryptedChat(high_id); + if (encryptedChat != null) { + enryptedLayer = AndroidUtilities.getPeerLayerVersion(encryptedChat.layer); + } + } + if (paths != null) { - for (int a = 0; a < paths.size(); a++) { + int count = paths.size(); + for (int a = 0; a < count; a++) { final String captionFinal = a == 0 ? caption : null; - if (!prepareSendingDocumentInternal(accountInstance, paths.get(a), originalPaths.get(a), null, mime, dialogId, replyToMsg, replyToTopMsg, captionFinal, null, editingMessageObject, false, notify, scheduleDate)) { + if (!isEncrypted && count > 1 && mediaCount % 10 == 0) { + if (groupId[0] != 0) { + finishGroup(accountInstance, groupId[0], scheduleDate); + } + groupId[0] = Utilities.random.nextLong(); + mediaCount = 0; + } + mediaCount++; + long prevGroupId = groupId[0]; + if (!prepareSendingDocumentInternal(accountInstance, paths.get(a), originalPaths.get(a), null, mime, dialogId, replyToMsg, replyToTopMsg, captionFinal, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, true, notify, scheduleDate, withThumb)) { error = true; } + if (prevGroupId != groupId[0]) { + mediaCount = 1; + } } } if (uris != null) { + groupId[0] = 0; + mediaCount = 0; + int count = uris.size(); for (int a = 0; a < uris.size(); a++) { final String captionFinal = a == 0 && (paths == null || paths.size() == 0) ? caption : null; - if (!prepareSendingDocumentInternal(accountInstance, null, null, uris.get(a), mime, dialogId, replyToMsg, replyToTopMsg, captionFinal, null, editingMessageObject, false, notify, scheduleDate)) { + if (!isEncrypted && count > 1 && mediaCount % 10 == 0) { + if (groupId[0] != 0) { + finishGroup(accountInstance, groupId[0], scheduleDate); + } + groupId[0] = Utilities.random.nextLong(); + mediaCount = 0; + } + mediaCount++; + long prevGroupId = groupId[0]; + if (!prepareSendingDocumentInternal(accountInstance, null, null, uris.get(a), mime, dialogId, replyToMsg, replyToTopMsg, captionFinal, null, editingMessageObject, groupId, mediaCount == 10 || a == count - 1, true, notify, scheduleDate, withThumb)) { error = true; } + if (prevGroupId != groupId[0]) { + mediaCount = 1; + } } } if (inputContent != null) { @@ -5549,8 +5681,14 @@ public class SendMessagesHelper extends BaseController implements NotificationCe @UiThread public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, CharSequence caption, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, boolean notify, int scheduleDate) { + prepareSendingPhoto(accountInstance, imageFilePath, null, imageUri, dialogId, replyToMsg, replyToTopMsg, caption, entities, stickers, inputContent, ttl, editingMessageObject, null, notify, scheduleDate); + } + + @UiThread + public static void prepareSendingPhoto(AccountInstance accountInstance, String imageFilePath, String thumbFilePath, Uri imageUri, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, CharSequence caption, ArrayList entities, ArrayList stickers, InputContentInfoCompat inputContent, int ttl, MessageObject editingMessageObject, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate) { SendingMediaInfo info = new SendingMediaInfo(); info.path = imageFilePath; + info.thumbPath = thumbFilePath; info.uri = imageUri; if (caption != null) { info.caption = caption.toString(); @@ -5560,6 +5698,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (stickers != null) { info.masks = new ArrayList<>(stickers); } + info.videoEditedInfo = videoEditedInfo; ArrayList infos = new ArrayList<>(); infos.add(info); prepareSendingMedia(accountInstance, infos, dialogId, replyToMsg, replyToTopMsg, inputContent, false, false, editingMessageObject, notify, scheduleDate); @@ -5861,14 +6000,17 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } accountInstance.getSendMessagesHelper().sendMessage(venue, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaGeo) { - if (result.send_message.period != 0) { + if (result.send_message.period != 0 || result.send_message.proximity_notification_radius != 0) { TLRPC.TL_messageMediaGeoLive location = new TLRPC.TL_messageMediaGeoLive(); - location.period = result.send_message.period; + location.period = result.send_message.period != 0 ? result.send_message.period : 900; location.geo = result.send_message.geo; + location.heading = result.send_message.heading; + location.proximity_notification_radius = result.send_message.proximity_notification_radius; accountInstance.getSendMessagesHelper().sendMessage(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } else { TLRPC.TL_messageMediaGeo location = new TLRPC.TL_messageMediaGeo(); location.geo = result.send_message.geo; + location.heading = result.send_message.heading; accountInstance.getSendMessagesHelper().sendMessage(location, dialogId, replyToMsg, replyToTopMsg, result.send_message.reply_markup, params, notify, scheduleDate); } } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaContact) { @@ -6018,17 +6160,17 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } @UiThread - public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList media, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, InputContentInfoCompat inputContent, boolean forceDocument, boolean groupPhotos, MessageObject editingMessageObject, boolean notify, int scheduleDate) { + public static void prepareSendingMedia(AccountInstance accountInstance, ArrayList media, long dialogId, MessageObject replyToMsg, MessageObject replyToTopMsg, InputContentInfoCompat inputContent, boolean forceDocument, boolean groupMedia, MessageObject editingMessageObject, boolean notify, int scheduleDate) { if (media.isEmpty()) { return; } for (int a = 0, N = media.size(); a < N; a++) { if (media.get(a).ttl > 0) { - groupPhotos = false; + groupMedia = false; break; } } - final boolean groupPhotosFinal = groupPhotos; + final boolean groupMediaFinal = groupMedia; mediaSendQueue.postRunnable(() -> { long beginTime = System.currentTimeMillis(); HashMap workers; @@ -6042,7 +6184,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe enryptedLayer = AndroidUtilities.getPeerLayerVersion(encryptedChat.layer); } } - if ((!isEncrypted || enryptedLayer >= 73) && !forceDocument && groupPhotosFinal) { + if ((!isEncrypted || enryptedLayer >= 73) && !forceDocument && groupMediaFinal) { workers = new HashMap<>(); for (int a = 0; a < count; a++) { final SendingMediaInfo info = media.get(a); @@ -6118,12 +6260,12 @@ public class SendMessagesHelper extends BaseController implements NotificationCe ArrayList> sendAsDocumentsEntities = null; String extension = null; - int photosCount = 0; + int mediaCount = 0; for (int a = 0; a < count; a++) { final SendingMediaInfo info = media.get(a); - if (groupPhotosFinal && (!isEncrypted || enryptedLayer >= 73) && count > 1 && photosCount % 10 == 0) { + if (groupMediaFinal && (!isEncrypted || enryptedLayer >= 73) && count > 1 && mediaCount % 10 == 0) { lastGroupId = groupId = Utilities.random.nextLong(); - photosCount = 0; + mediaCount = 0; } if (info.searchImage != null && info.videoEditedInfo == null) { if (info.searchImage.type == 1) { @@ -6156,7 +6298,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe document.attributes.add(fileName); document.size = info.searchImage.size; document.dc_id = 0; - if (cacheFile.toString().endsWith("mp4")) { + if (!forceDocument && cacheFile.toString().endsWith("mp4")) { document.mime_type = "video/mp4"; document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); } else { @@ -6279,10 +6421,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFinal != null) { params.put("parentObject", parentFinal); } - if (groupPhotosFinal) { - photosCount++; + if (groupMediaFinal) { + mediaCount++; params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count -1) { + if (mediaCount == 10 || a == count -1) { params.put("final", "1"); lastGroupId = 0; } @@ -6442,10 +6584,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe if (parentFinal != null) { params.put("parentObject", parentFinal); } - if (!muted && groupPhotosFinal) { - photosCount++; + if (!muted && groupMediaFinal) { + mediaCount++; params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count -1) { + if (mediaCount == 10 || a == count -1) { params.put("final", "1"); lastGroupId = 0; } @@ -6471,7 +6613,19 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } }); } else { - prepareSendingDocumentInternal(accountInstance, info.path, info.path, null, null, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, editingMessageObject, forceDocument, notify, scheduleDate); + if (sendAsDocuments == null) { + sendAsDocuments = new ArrayList<>(); + sendAsDocumentsOriginal = new ArrayList<>(); + sendAsDocumentsCaptions = new ArrayList<>(); + sendAsDocumentsEntities = new ArrayList<>(); + sendAsDocumentsUri = new ArrayList<>(); + } + sendAsDocuments.add(info.path); + sendAsDocumentsOriginal.add(info.path); + sendAsDocumentsUri.add(info.uri); + sendAsDocumentsCaptions.add(info.caption); + sendAsDocumentsEntities.add(info.entities); + //prepareSendingDocumentInternal(accountInstance, info.path, info.path, null, null, dialogId, replyToMsg, replyToTopMsg, info.caption, info.entities, editingMessageObject, null, false, forceDocument, notify, scheduleDate, null); } } else { String originalPath = info.path; @@ -6623,7 +6777,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } try { - if (!groupPhotosFinal || media.size() == 1) { + if (!groupMediaFinal || media.size() == 1) { TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photoFinal.sizes, AndroidUtilities.getPhotoSize()); if (currentPhotoObject != null) { keyFinal[0] = getKeyForPhotoSize(currentPhotoObject, bitmapFinal, false, false); @@ -6633,10 +6787,10 @@ public class SendMessagesHelper extends BaseController implements NotificationCe FileLog.e(e); } - if (groupPhotosFinal) { - photosCount++; + if (groupMediaFinal) { + mediaCount++; params.put("groupId", "" + groupId); - if (photosCount == 10 || a == count - 1) { + if (mediaCount == 10 || a == count - 1) { params.put("final", "1"); lastGroupId = 0; } @@ -6670,31 +6824,21 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } } if (lastGroupId != 0) { - final long lastGroupIdFinal = lastGroupId; - AndroidUtilities.runOnUIThread(() -> { - SendMessagesHelper instance = accountInstance.getSendMessagesHelper(); - ArrayList arrayList = instance.delayedMessages.get("group_" + lastGroupIdFinal); - if (arrayList != null && !arrayList.isEmpty()) { - - DelayedMessage message = arrayList.get(0); - - MessageObject prevMessage = message.messageObjects.get(message.messageObjects.size() - 1); - message.finalGroupMessage = prevMessage.getId(); - prevMessage.messageOwner.params.put("final", "1"); - - TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); - messagesRes.messages.add(prevMessage.messageOwner); - accountInstance.getMessagesStorage().putMessages(messagesRes, message.peer, -2, 0, false, scheduleDate != 0); - instance.sendReadyToSendGroup(message, true, true); - } - }); + finishGroup(accountInstance, lastGroupId, scheduleDate); } if (inputContent != null) { inputContent.releasePermission(); } if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { - for (int a = 0; a < sendAsDocuments.size(); a++) { - prepareSendingDocumentInternal(accountInstance, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), sendAsDocumentsUri.get(a), extension, dialogId, replyToMsg, replyToTopMsg, sendAsDocumentsCaptions.get(a), sendAsDocumentsEntities.get(a), editingMessageObject, forceDocument, notify, scheduleDate); + long[] groupId2 = new long[1]; + int documentsCount = sendAsDocuments.size(); + for (int a = 0; a < documentsCount; a++) { + if (forceDocument && !isEncrypted && count > 1 && mediaCount % 10 == 0) { + groupId2[0] = Utilities.random.nextLong(); + mediaCount = 0; + } + mediaCount++; + prepareSendingDocumentInternal(accountInstance, sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), sendAsDocumentsUri.get(a), extension, dialogId, replyToMsg, replyToTopMsg, sendAsDocumentsCaptions.get(a), sendAsDocumentsEntities.get(a), editingMessageObject, groupId2, mediaCount == 10 || a == documentsCount - 1, forceDocument, notify, scheduleDate, null); } } if (BuildVars.LOGS_ENABLED) { @@ -7103,7 +7247,7 @@ public class SendMessagesHelper extends BaseController implements NotificationCe } }); } else { - prepareSendingDocumentInternal(accountInstance, videoPath, videoPath, null, null, dialogId, replyToMsg, replyToTopMsg, caption, entities, editingMessageObject, false, notify, scheduleDate); + prepareSendingDocumentInternal(accountInstance, videoPath, videoPath, null, null, dialogId, replyToMsg, replyToTopMsg, caption, entities, editingMessageObject, null, false, false, notify, scheduleDate, null); } }).start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java index 355411ed5..c5018990f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -323,7 +323,11 @@ public class Browser { } public static boolean isInternalUrl(String url, boolean[] forceBrowser) { - return isInternalUri(Uri.parse(url), forceBrowser); + return isInternalUri(Uri.parse(url), false, forceBrowser); + } + + public static boolean isInternalUrl(String url, boolean all, boolean[] forceBrowser) { + return isInternalUri(Uri.parse(url), all, forceBrowser); } public static boolean isPassportUrl(String url) { @@ -342,6 +346,10 @@ public class Browser { } public static boolean isInternalUri(Uri uri, boolean[] forceBrowser) { + return isInternalUri(uri, false, forceBrowser); + } + + public static boolean isInternalUri(Uri uri, boolean all, boolean[] forceBrowser) { String host = uri.getHost(); host = host != null ? host.toLowerCase() : ""; if ("ton".equals(uri.getScheme())) { @@ -365,6 +373,9 @@ public class Browser { } else if ("telegram.dog".equals(host)) { String path = uri.getPath(); if (path != null && path.length() > 1) { + if (all) { + return true; + } path = path.substring(1).toLowerCase(); if (path.startsWith("blog") || path.equals("iv") || path.startsWith("faq") || path.equals("apps") || path.startsWith("s/")) { if (forceBrowser != null) { @@ -377,6 +388,9 @@ public class Browser { } else if ("telegram.me".equals(host) || "t.me".equals(host)) { String path = uri.getPath(); if (path != null && path.length() > 1) { + if (all) { + return true; + } path = path.substring(1).toLowerCase(); if (path.equals("iv") || path.startsWith("s/")) { if (forceBrowser != null) { @@ -386,6 +400,10 @@ public class Browser { } return true; } + } else if (all) { + if (host.endsWith("telegram.org") || host.endsWith("telegra.ph") || host.endsWith("telesco.pe")) { + return true; + } } return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java index 513ffa95b..4787d818f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -388,7 +388,7 @@ public class TextureRenderer { for (int a = 0, N = mediaEntities.size(); a < N; a++) { VideoEditedInfo.MediaEntity entity = mediaEntities.get(a); if (entity.ptr != 0) { - RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes()); + RLottieDrawable.getFrame(entity.ptr, (int) entity.currentFrame, stickerBitmap, 512, 512, stickerBitmap.getRowBytes(), true); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, stickerTexture[0]); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, stickerBitmap, 0); entity.currentFrame += entity.framesPerDraw; diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java index 2cdf3e845..b4ae2da0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -231,6 +231,10 @@ public class ConnectionsManager extends BaseController { return native_getCurrentTime(currentAccount); } + public int getCurrentDatacenterId() { + return native_getCurrentDatacenterId(currentAccount); + } + public int getTimeDifference() { return native_getTimeDifference(currentAccount); } @@ -520,6 +524,9 @@ public class ConnectionsManager extends BaseController { int flags = 0; EmuDetector detector = EmuDetector.with(ApplicationLoader.applicationContext); if (detector.detect()) { + if (BuildVars.LOGS_ENABLED) { + FileLog.d("detected emu"); + } flags |= 1024; } return flags; @@ -538,7 +545,7 @@ public class ConnectionsManager extends BaseController { boolean networkOnline = ApplicationLoader.isNetworkOnline(); Utilities.stageQueue.postRunnable(() -> { - if (currentTask != null || second == 0 && Math.abs(lastDnsRequestTime - System.currentTimeMillis()) < 10000 || !networkOnline) { + if (currentTask != null || second == 0 && Math.abs(lastDnsRequestTime - System.currentTimeMillis()) < 10000 || !networkOnline) { if (BuildVars.LOGS_ENABLED) { FileLog.d("don't start task, current task = " + currentTask + " next task = " + second + " time diff = " + Math.abs(lastDnsRequestTime - System.currentTimeMillis()) + " network = " + ApplicationLoader.isNetworkOnline()); } @@ -547,12 +554,12 @@ public class ConnectionsManager extends BaseController { lastDnsRequestTime = System.currentTimeMillis(); - if (BuildVars.LOGS_ENABLED) { - FileLog.d("start dns txt task"); - } - DnsTxtLoadTask task = new DnsTxtLoadTask(currentAccount); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); - currentTask = task; + if (BuildVars.LOGS_ENABLED) { + FileLog.d("start dns txt task"); + } + DnsTxtLoadTask task = new DnsTxtLoadTask(currentAccount); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); + currentTask = task; }); }); @@ -657,6 +664,8 @@ public class ConnectionsManager extends BaseController { public static native int native_getCurrentTime(int currentAccount); + public static native int native_getCurrentDatacenterId(int currentAccount); + public static native int native_getTimeDifference(int currentAccount); public static native void native_sendRequest(int currentAccount, long object, RequestDelegateInternal onComplete, QuickAckDelegate onQuickAck, WriteToSocketDelegate onWriteToSocket, int flags, int datacenterId, int connetionType, boolean immediate, int requestToken); diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java index c1a9c5051..c56a57c13 100644 --- a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -61,7 +61,7 @@ public class TLRPC { public static final int MESSAGE_FLAG_EDITED = 0x00008000; public static final int MESSAGE_FLAG_MEGAGROUP = 0x80000000; - public static final int LAYER = 119; + public static final int LAYER = 120; public static class TL_stats_megagroupStats extends TLObject { public static int constructor = 0xef7ff916; @@ -2429,19 +2429,20 @@ public class TLRPC { public int pts; public int count; public int next_rate; + public int offset_id_offset; public static messages_Messages TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { messages_Messages result = null; switch (constructor) { + case 0x3a54685e: + result = new TL_messages_messagesSlice(); + break; case 0x8c718e87: result = new TL_messages_messages(); break; - case 0x99262e37: + case 0x64479808: result = new TL_messages_channelMessages(); break; - case 0xc8edce1e: - result = new TL_messages_messagesSlice(); - break; case 0x74535f21: result = new TL_messages_messagesNotModified(); break; @@ -2456,6 +2457,99 @@ public class TLRPC { } } + public static class TL_messages_messagesSlice extends messages_Messages { + public static int constructor = 0x3a54685e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + inexact = (flags & 2) != 0; + count = stream.readInt32(exception); + if ((flags & 1) != 0) { + next_rate = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + offset_id_offset = 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++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.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); + flags = inexact ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(count); + if ((flags & 1) != 0) { + stream.writeInt32(next_rate); + } + if ((flags & 4) != 0) { + stream.writeInt32(offset_id_offset); + } + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.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(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + public static class TL_messages_messages extends messages_Messages { public static int constructor = 0x8c718e87; @@ -2532,7 +2626,7 @@ public class TLRPC { } public static class TL_messages_channelMessages extends messages_Messages { - public static int constructor = 0x99262e37; + public static int constructor = 0x64479808; public void readParams(AbstractSerializedData stream, boolean exception) { @@ -2540,6 +2634,9 @@ public class TLRPC { inexact = (flags & 2) != 0; pts = stream.readInt32(exception); count = stream.readInt32(exception); + if ((flags & 4) != 0) { + offset_id_offset = stream.readInt32(exception); + } int magic = stream.readInt32(exception); if (magic != 0x1cb5c415) { if (exception) { @@ -2593,92 +2690,8 @@ public class TLRPC { stream.writeInt32(flags); stream.writeInt32(pts); stream.writeInt32(count); - stream.writeInt32(0x1cb5c415); - int count = messages.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - messages.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(0x1cb5c415); - count = users.size(); - stream.writeInt32(count); - for (int a = 0; a < count; a++) { - users.get(a).serializeToStream(stream); - } - } - } - - public static class TL_messages_messagesSlice extends messages_Messages { - public static int constructor = 0xc8edce1e; - - - public void readParams(AbstractSerializedData stream, boolean exception) { - flags = stream.readInt32(exception); - inexact = (flags & 2) != 0; - count = stream.readInt32(exception); - if ((flags & 1) != 0) { - next_rate = 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++) { - Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - messages.add(object); - } - magic = stream.readInt32(exception); - if (magic != 0x1cb5c415) { - if (exception) { - throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); - } - return; - } - count = stream.readInt32(exception); - for (int a = 0; a < count; a++) { - Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); - if (object == null) { - return; - } - chats.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); - flags = inexact ? (flags | 2) : (flags &~ 2); - stream.writeInt32(flags); - stream.writeInt32(count); - if ((flags & 1) != 0) { - stream.writeInt32(next_rate); + if ((flags & 4) != 0) { + stream.writeInt32(offset_id_offset); } stream.writeInt32(0x1cb5c415); int count = messages.size(); @@ -4352,15 +4365,17 @@ public class TLRPC { } public static abstract class GeoPoint extends TLObject { - public double _long; - public double lat; + public int flags; + public double _long; + public double lat; + public int accuracy_radius; public long access_hash; public static GeoPoint TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { GeoPoint result = null; switch (constructor) { case 0x296f104: - result = new TL_geoPoint(); + result = new TL_geoPoint_layer119(); break; case 0x2049d70c: result = new TL_geoPoint_layer81(); @@ -4368,6 +4383,9 @@ public class TLRPC { case 0x1117dd5f: result = new TL_geoPointEmpty(); break; + case 0xb2a2f663: + result = new TL_geoPoint(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in GeoPoint", constructor)); @@ -4379,7 +4397,7 @@ public class TLRPC { } } - public static class TL_geoPoint extends GeoPoint { + public static class TL_geoPoint_layer119 extends TL_geoPoint { public static int constructor = 0x296f104; @@ -4422,6 +4440,32 @@ public class TLRPC { } } + public static class TL_geoPoint extends GeoPoint { + public static int constructor = 0xb2a2f663; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + _long = stream.readDouble(exception); + lat = stream.readDouble(exception); + access_hash = stream.readInt64(exception); + if ((flags & 1) != 0) { + accuracy_radius = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeDouble(_long); + stream.writeDouble(lat); + stream.writeInt64(access_hash); + if ((flags & 1) != 0) { + stream.writeInt32(accuracy_radius); + } + } + } + public static class TL_account_privacyRules extends TLObject { public static int constructor = 0x50a04e45; @@ -6352,7 +6396,37 @@ public class TLRPC { } } - public static class TL_messageMediaGeoLive extends MessageMedia { + public static class TL_messageMediaGeoLive extends MessageMedia { + public static int constructor = 0xb940c666; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + heading = stream.readInt32(exception); + } + period = stream.readInt32(exception); + if ((flags & 2) != 0) { + proximity_notification_radius = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(heading); + } + stream.writeInt32(period); + if ((flags & 2) != 0) { + stream.writeInt32(proximity_notification_radius); + } + } + } + + public static class TL_messageMediaGeoLive_layer119 extends TL_messageMediaGeoLive { public static int constructor = 0x7c3c2609; @@ -7573,15 +7647,18 @@ public class TLRPC { } public static abstract class InputGeoPoint extends TLObject { - public double lat; - public double _long; + + public int flags; + public double lat; + public double _long; + public int accuracy_radius; public static InputGeoPoint TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { InputGeoPoint result = null; switch (constructor) { - case 0xf3b7acc9: - result = new TL_inputGeoPoint(); - break; + case 0x48222faf: + result = new TL_inputGeoPoint(); + break; case 0xe4c123d6: result = new TL_inputGeoPointEmpty(); break; @@ -7596,21 +7673,29 @@ public class TLRPC { } } - public static class TL_inputGeoPoint extends InputGeoPoint { - public static int constructor = 0xf3b7acc9; + public static class TL_inputGeoPoint extends InputGeoPoint { + public static int constructor = 0x48222faf; - public void readParams(AbstractSerializedData stream, boolean exception) { - lat = stream.readDouble(exception); - _long = stream.readDouble(exception); - } + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + if ((flags & 1) != 0) { + accuracy_radius = stream.readInt32(exception); + } + } - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeDouble(lat); - stream.writeDouble(_long); - } - } + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeDouble(lat); + stream.writeDouble(_long); + if ((flags & 1) != 0) { + stream.writeInt32(accuracy_radius); + } + } + } public static class TL_inputGeoPointEmpty extends InputGeoPoint { public static int constructor = 0xe4c123d6; @@ -12203,6 +12288,8 @@ public class TLRPC { public String vcard; public boolean no_webpage; public int period; + public int heading; + public int proximity_notification_radius; public static BotInlineMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { BotInlineMessage result = null; @@ -12232,8 +12319,11 @@ public class TLRPC { result = new TL_botInlineMessageText(); break; case 0xb722de65: - result = new TL_botInlineMessageMediaGeo(); + result = new TL_botInlineMessageMediaGeo_layer119(); break; + case 0x51846fd: + result = new TL_botInlineMessageMediaGeo(); + break; } if (result == null && exception) { throw new RuntimeException(String.format("can't parse magic %x in BotInlineMessage", constructor)); @@ -12499,7 +12589,47 @@ public class TLRPC { } } - public static class TL_botInlineMessageMediaGeo extends BotInlineMessage { + public static class TL_botInlineMessageMediaGeo extends BotInlineMessage { + public static int constructor = 0x51846fd; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 1) != 0) { + heading = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + period = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + proximity_notification_radius = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(heading); + } + if ((flags & 2) != 0) { + stream.writeInt32(period); + } + if ((flags & 8) != 0) { + stream.writeInt32(proximity_notification_radius); + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageMediaGeo_layer119 extends TL_botInlineMessageMediaGeo { public static int constructor = 0xb722de65; @@ -16175,6 +16305,9 @@ public class TLRPC { public static ChannelParticipantsFilter TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { ChannelParticipantsFilter result = null; switch (constructor) { + case 0xe04b5ceb: + result = new TL_channelParticipantsMentions(); + break; case 0xbb6ae88d: result = new TL_channelParticipantsContacts(); break; @@ -16207,6 +16340,34 @@ public class TLRPC { } } + public static class TL_channelParticipantsMentions extends ChannelParticipantsFilter { + public static int constructor = 0xe04b5ceb; + + public int flags; + public int top_msg_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + q = stream.readString(exception); + } + if ((flags & 2) != 0) { + top_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeString(q); + } + if ((flags & 2) != 0) { + stream.writeInt32(top_msg_id); + } + } + } + public static class TL_channelParticipantsContacts extends ChannelParticipantsFilter { public static int constructor = 0xbb6ae88d; @@ -16383,6 +16544,9 @@ public class TLRPC { case 0x94bd38ed: result = new TL_messageActionPinMessage(); break; + case 0x98e0d697: + result = new TL_messageActionGeoProximityReached(); + break; case 0x95e3fbef: result = new TL_messageActionChatDeletePhoto(); break; @@ -16757,6 +16921,27 @@ public class TLRPC { } } + public static class TL_messageActionGeoProximityReached extends MessageAction { + public static int constructor = 0x98e0d697; + + public Peer from_id; + public Peer to_id; + public int distance; + + public void readParams(AbstractSerializedData stream, boolean exception) { + from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + distance = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + from_id.serializeToStream(stream); + to_id.serializeToStream(stream); + stream.writeInt32(distance); + } + } + public static class TL_messageActionChatDeletePhoto extends MessageAction { public static int constructor = 0x95e3fbef; @@ -20533,6 +20718,7 @@ public class TLRPC { public String provider; public String venue_id; public String venue_type; + public int heading; public int period; public boolean nosound_video; public boolean force_file; @@ -20540,6 +20726,7 @@ public class TLRPC { public InputFile thumb; public String mime_type; public ArrayList attributes = new ArrayList<>(); + public int proximity_notification_radius; public static InputMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { InputMedia result = null; @@ -20574,7 +20761,7 @@ public class TLRPC { case 0xc13d1c11: result = new TL_inputMediaVenue(); break; - case 0xce4e82fd: + case 0x971fa843: result = new TL_inputMediaGeoLive(); break; case 0x5b38c6c1: @@ -20859,16 +21046,22 @@ public class TLRPC { } public static class TL_inputMediaGeoLive extends InputMedia { - public static int constructor = 0xce4e82fd; + public static int constructor = 0x971fa843; public void readParams(AbstractSerializedData stream, boolean exception) { flags = stream.readInt32(exception); stopped = (flags & 1) != 0; geo_point = InputGeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + heading = stream.readInt32(exception); + } if ((flags & 2) != 0) { period = stream.readInt32(exception); } + if ((flags & 8) != 0) { + proximity_notification_radius = stream.readInt32(exception); + } } public void serializeToStream(AbstractSerializedData stream) { @@ -20876,9 +21069,15 @@ public class TLRPC { flags = stopped ? (flags | 1) : (flags &~ 1); stream.writeInt32(flags); geo_point.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt32(heading); + } if ((flags & 2) != 0) { stream.writeInt32(period); } + if ((flags & 8) != 0) { + stream.writeInt32(proximity_notification_radius); + } } } @@ -21727,12 +21926,12 @@ public class TLRPC { case 0xaca1657b: result = new TL_updateMessagePoll(); break; - case 0x4c43da18: - result = new TL_updateUserPinnedMessage(); - break; case 0xa20db0e5: result = new TL_updateDeleteMessages(); break; + case 0x8588878b: + result = new TL_updatePinnedChannelMessages(); + break; case 0x571d2742: result = new TL_updateReadFeaturedStickers(); break; @@ -21796,9 +21995,6 @@ public class TLRPC { case 0x6e5f8c22: result = new TL_updateChatParticipantDelete(); break; - case 0xe10db349: - result = new TL_updateChatPinnedMessage(); - break; case 0xe40370a3: result = new TL_updateEditMessage(); break; @@ -21835,9 +22031,6 @@ public class TLRPC { case 0xebe46819: result = new TL_updateServiceNotification(); break; - case 0x98592475: - result = new TL_updateChannelPinnedMessage(); - break; case 0x56022f4d: result = new TL_updateLangPack(); break; @@ -21928,6 +22121,9 @@ public class TLRPC { case 0x246a4b22: result = new TL_updatePeerBlocked(); break; + case 0xed85eab5: + result = new TL_updatePinnedMessages(); + break; case 0x8e5e9873: result = new TL_updateDcOptions(); break; @@ -21972,24 +22168,6 @@ public class TLRPC { } } - public static class TL_updateUserPinnedMessage extends Update { - public static int constructor = 0x4c43da18; - - public int user_id; - public int id; - - public void readParams(AbstractSerializedData stream, boolean exception) { - user_id = stream.readInt32(exception); - id = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(user_id); - stream.writeInt32(id); - } - } - public static class TL_updateDeleteMessages extends Update { public static int constructor = 0xa20db0e5; @@ -22026,6 +22204,51 @@ public class TLRPC { } } + public static class TL_updatePinnedChannelMessages extends Update { + public static int constructor = 0x8588878b; + + public int flags; + public boolean pinned; + public int channel_id; + public ArrayList messages = new ArrayList<>(); + public int pts; + public int pts_count; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 1) != 0; + channel_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++) { + messages.add(stream.readInt32(exception)); + } + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(channel_id); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(messages.get(a)); + } + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + public static class TL_updateReadFeaturedStickers extends Update { public static int constructor = 0x571d2742; @@ -22453,27 +22676,6 @@ public class TLRPC { } } - public static class TL_updateChatPinnedMessage extends Update { - public static int constructor = 0xe10db349; - - public int chat_id; - public int id; - public int version; - - public void readParams(AbstractSerializedData stream, boolean exception) { - chat_id = stream.readInt32(exception); - id = stream.readInt32(exception); - version = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(chat_id); - stream.writeInt32(id); - stream.writeInt32(version); - } - } - public static class TL_updateEditMessage extends Update { public static int constructor = 0xe40370a3; @@ -22776,24 +22978,6 @@ public class TLRPC { } } - public static class TL_updateChannelPinnedMessage extends Update { - public static int constructor = 0x98592475; - - public int channel_id; - public int id; - - public void readParams(AbstractSerializedData stream, boolean exception) { - channel_id = stream.readInt32(exception); - id = stream.readInt32(exception); - } - - public void serializeToStream(AbstractSerializedData stream) { - stream.writeInt32(constructor); - stream.writeInt32(channel_id); - stream.writeInt32(id); - } - } - public static class TL_updateLangPack extends Update { public static int constructor = 0x56022f4d; @@ -23487,6 +23671,51 @@ public class TLRPC { } } + public static class TL_updatePinnedMessages extends Update { + public static int constructor = 0xed85eab5; + + public int flags; + public boolean pinned; + public Peer peer; + public ArrayList messages = new ArrayList<>(); + public int pts; + public int pts_count; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pinned = (flags & 1) != 0; + peer = Peer.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++) { + messages.add(stream.readInt32(exception)); + } + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = pinned ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(messages.get(a)); + } + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + public static class TL_updateDcOptions extends Update { public static int constructor = 0x8e5e9873; @@ -28241,6 +28470,9 @@ public class TLRPC { switch (constructor) { case 0x1c0facaf: result = new TL_channelParticipantBanned(); + break; + case 0xc3c6796b: + result = new TL_channelParticipantLeft(); break; case 0x222c1886: result = new TL_channelParticipantBanned_layer92(); @@ -28313,6 +28545,20 @@ public class TLRPC { } } + public static class TL_channelParticipantLeft extends ChannelParticipant { + public static int constructor = 0xc3c6796b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + public static class TL_channelParticipantCreator_layer103 extends TL_channelParticipantCreator { public static int constructor = 0xe3e2e1f9; @@ -32270,6 +32516,9 @@ public class TLRPC { case 0xe7026d0d: result = new TL_inputMessagesFilterGeo(); break; + case 0x1bb00451: + result = new TL_inputMessagesFilterPinned(); + break; case 0xc1f8e69a: result = new TL_inputMessagesFilterMyMentions(); break; @@ -32386,6 +32635,15 @@ public class TLRPC { } } + public static class TL_inputMessagesFilterPinned extends MessagesFilter { + public static int constructor = 0x1bb00451; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + public static class TL_inputMessagesFilterMyMentions extends MessagesFilter { public static int constructor = 0xc1f8e69a; @@ -36890,12 +37148,12 @@ public class TLRPC { } public static class TL_messages_search extends TLObject { - public static int constructor = 0x4e17810b; + public static int constructor = 0xc352eec; public int flags; public InputPeer peer; public String q; - public InputUser from_id; + public InputPeer from_id; public int top_msg_id; public MessagesFilter filter; public int min_date; @@ -40287,6 +40545,8 @@ public class TLRPC { public int flags; public boolean silent; + public boolean unpin; + public boolean pm_oneside; public InputPeer peer; public int id; @@ -40297,6 +40557,8 @@ public class TLRPC { public void serializeToStream(AbstractSerializedData stream) { stream.writeInt32(constructor); flags = silent ? (flags | 1) : (flags &~ 1); + flags = unpin ? (flags | 2) : (flags &~ 2); + flags = pm_oneside ? (flags | 4) : (flags &~ 4); stream.writeInt32(flags); peer.serializeToStream(stream); stream.writeInt32(id); @@ -40963,6 +41225,21 @@ public class TLRPC { } } + public static class TL_messages_unpinAllMessages extends TLObject { + public static int constructor = 0xf025bc8b; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedHistory.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + public static class TL_help_getAppChangelog extends TLObject { public static int constructor = 0x9010ef6f; @@ -42761,6 +43038,7 @@ public class TLRPC { public boolean shipping_address_requested; public Photo photo; public GeoPoint geo; + public int heading; public String currency; public String description; public int receipt_msg_id; @@ -42784,6 +43062,7 @@ public class TLRPC { public boolean test; public int period; public int ttl_seconds; + public int proximity_notification_radius; public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { MessageMedia result = null; @@ -42809,8 +43088,11 @@ public class TLRPC { case 0x7912b71f: result = new TL_messageMediaVenue_layer71(); break; + case 0xb940c666: + result = new TL_messageMediaGeoLive(); + break; case 0x7c3c2609: - result = new TL_messageMediaGeoLive(); + result = new TL_messageMediaGeoLive_layer119(); break; case 0x2ec0533f: result = new TL_messageMediaVenue(); @@ -43284,6 +43566,7 @@ public class TLRPC { public boolean from_scheduled; public boolean legacy; public boolean edit_hide; + public boolean pinned; public MessageFwdHeader fwd_from; public int via_bot_id; public TL_messageReplyHeader reply_to; @@ -44066,6 +44349,7 @@ public class TLRPC { from_scheduled = (flags & 262144) != 0; legacy = (flags & 524288) != 0; edit_hide = (flags & 2097152) != 0; + pinned = (flags & 16777216) != 0; id = stream.readInt32(exception); if ((flags & 256) != 0) { from_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); @@ -44158,6 +44442,7 @@ public class TLRPC { flags = from_scheduled ? (flags | 262144) : (flags &~ 262144); flags = legacy ? (flags | 524288) : (flags &~ 524288); flags = edit_hide ? (flags | 2097152) : (flags &~ 2097152); + flags = pinned ? (flags | 16777216) : (flags &~ 16777216); stream.writeInt32(flags); stream.writeInt32(id); if ((flags & 256) != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index 4ecb705cd..f1e385da6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -957,9 +957,16 @@ public class ActionBarLayout extends FrameLayout { layoutParams.width = LayoutHelper.MATCH_PARENT; layoutParams.height = LayoutHelper.MATCH_PARENT; if (preview) { + int height = fragment.getPreviewHeight(); + int statusBarHeight = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); + if (height > 0 && height < getMeasuredHeight() - statusBarHeight) { + layoutParams.height = height; + layoutParams.topMargin = statusBarHeight + (getMeasuredHeight() - statusBarHeight - height) / 2; + } else { + layoutParams.topMargin = layoutParams.bottomMargin = AndroidUtilities.dp(46); + layoutParams.topMargin += AndroidUtilities.statusBarHeight; + } layoutParams.rightMargin = layoutParams.leftMargin = AndroidUtilities.dp(8); - layoutParams.topMargin = layoutParams.bottomMargin = AndroidUtilities.dp(46); - layoutParams.topMargin += AndroidUtilities.statusBarHeight; } else { layoutParams.topMargin = layoutParams.bottomMargin = layoutParams.rightMargin = layoutParams.leftMargin = 0; } @@ -1076,7 +1083,8 @@ public class ActionBarLayout extends FrameLayout { fragment.onTransitionAnimationEnd(true, false); fragment.onBecomeFullyVisible(); }; - if (!fragment.needDelayOpenAnimation()) { + boolean noDelay; + if (noDelay = !fragment.needDelayOpenAnimation()) { if (currentFragment != null) { currentFragment.onTransitionAnimationStart(false, false); } @@ -1107,6 +1115,12 @@ public class ActionBarLayout extends FrameLayout { return; } waitingForKeyboardCloseRunnable = null; + if (!noDelay) { + if (currentFragment != null) { + currentFragment.onTransitionAnimationStart(false, false); + } + fragment.onTransitionAnimationStart(true, false); + } startLayoutAnimation(true, true, preview); } }; @@ -1192,6 +1206,7 @@ public class ActionBarLayout extends FrameLayout { fragment.setParentLayout(null); fragmentsStack.remove(fragment); containerViewBack.setVisibility(View.INVISIBLE); + containerViewBack.setTranslationY(0); bringChildToFront(containerView); } @@ -1217,6 +1232,7 @@ public class ActionBarLayout extends FrameLayout { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) fragment.fragmentView.getLayoutParams(); layoutParams.topMargin = layoutParams.bottomMargin = layoutParams.rightMargin = layoutParams.leftMargin = 0; + layoutParams.height = LayoutHelper.MATCH_PARENT; fragment.fragmentView.setLayoutParams(layoutParams); presentFragmentInternalRemoveOld(false, prevFragment); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 62b293e7a..a4902ddde 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -737,20 +737,21 @@ public class ActionBarMenuItem extends FrameLayout { }.setDuration(150)).addTransition(changeBounds); transition.setOrdering(TransitionSet.ORDERING_TOGETHER); transition.setInterpolator(CubicBezierInterpolator.EASE_OUT); + int selectedAccount = UserConfig.selectedAccount; transition.addListener(new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) { - notificationIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(notificationIndex,null); + notificationIndex = NotificationCenter.getInstance(selectedAccount).setAnimationInProgress(notificationIndex,null); } @Override public void onTransitionEnd(Transition transition) { - NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(notificationIndex); + NotificationCenter.getInstance(selectedAccount).onAnimationFinish(notificationIndex); } @Override public void onTransitionCancel(Transition transition) { - NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(notificationIndex); + NotificationCenter.getInstance(selectedAccount).onAnimationFinish(notificationIndex); } @Override @@ -950,8 +951,10 @@ public class ActionBarMenuItem extends FrameLayout { } else { if (searchFieldCaption.getVisibility() == VISIBLE) { measureChildWithMargins(searchFieldCaption, widthMeasureSpec, MeasureSpec.getSize(widthMeasureSpec) / 2, heightMeasureSpec, 0); + width = searchFieldCaption.getMeasuredWidth() + AndroidUtilities.dp(4); + } else { + width = 0; } - width = 0; int minWidth = MeasureSpec.getSize(widthMeasureSpec); ignoreRequestLayout = true; measureChildWithMargins(searchFilterLayout, widthMeasureSpec, width, heightMeasureSpec, 0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java index 7fd6e3257..b4593c32d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java @@ -37,7 +37,9 @@ import android.widget.ScrollView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.ui.Components.LayoutHelper; import java.lang.reflect.Field; @@ -54,6 +56,9 @@ public class ActionBarPopupWindow extends PopupWindow { private AnimatorSet windowAnimatorSet; private boolean animationEnabled = allowAnimation; private int dismissAnimationDuration = 150; + private boolean isClosingAnimated; + private int currentAccount = UserConfig.selectedAccount; + private boolean pauseNotifications; static { Field f = null; @@ -72,6 +77,7 @@ public class ActionBarPopupWindow extends PopupWindow { private ViewTreeObserver.OnScrollChangedListener mSuperScrollListener; private ViewTreeObserver mViewTreeObserver; + private int popupAnimationIndex = -1; public interface OnDispatchKeyEventListener { void onDispatchKeyEvent(KeyEvent keyEvent); @@ -441,12 +447,7 @@ public class ActionBarPopupWindow extends PopupWindow { ObjectAnimator.ofInt(content, "backAlpha", 0, 255)); windowAnimatorSet.setDuration(150 + 16 * visibleCount); int finalCount = count; - windowAnimatorSet.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - - } - + windowAnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { windowAnimatorSet = null; @@ -456,16 +457,6 @@ public class ActionBarPopupWindow extends PopupWindow { child.setAlpha(1.0f); } } - - @Override - public void onAnimationCancel(Animator animation) { - onAnimationEnd(animation); - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } }); windowAnimatorSet.start(); } @@ -494,12 +485,22 @@ public class ActionBarPopupWindow extends PopupWindow { dismiss(true); } + public void setPauseNotifications(boolean value) { + pauseNotifications = value; + } + public void dismiss(boolean animated) { setFocusable(false); - if (animationEnabled && animated) { - if (windowAnimatorSet != null) { - windowAnimatorSet.cancel(); + if (windowAnimatorSet != null) { + if (animated && isClosingAnimated) { + return; } + windowAnimatorSet.cancel(); + windowAnimatorSet = null; + } + isClosingAnimated = false; + if (animationEnabled && animated) { + isClosingAnimated = true; ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView(); if (content.itemAnimators != null && !content.itemAnimators.isEmpty()) { for (int a = 0, N = content.itemAnimators.size(); a < N; a++) { @@ -514,15 +515,11 @@ public class ActionBarPopupWindow extends PopupWindow { ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, AndroidUtilities.dp(content.showedFromBotton ? 5 : -5)), ObjectAnimator.ofFloat(content, View.ALPHA, 0.0f)); windowAnimatorSet.setDuration(dismissAnimationDuration); - windowAnimatorSet.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - - } - + windowAnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { windowAnimatorSet = null; + isClosingAnimated = false; setFocusable(false); try { ActionBarPopupWindow.super.dismiss(); @@ -530,18 +527,14 @@ public class ActionBarPopupWindow extends PopupWindow { } unregisterListener(); - } - - @Override - public void onAnimationCancel(Animator animation) { - onAnimationEnd(animation); - } - - @Override - public void onAnimationRepeat(Animator animation) { - + if (pauseNotifications) { + NotificationCenter.getInstance(currentAccount).onAnimationFinish(popupAnimationIndex); + } } }); + if (pauseNotifications) { + popupAnimationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(popupAnimationIndex, null); + } windowAnimatorSet.start(); } else { try { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java index d6ea991b3..6079f4543 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AdjustPanLayoutHelper.java @@ -13,8 +13,6 @@ import android.view.Window; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import com.google.android.exoplayer2.util.Log; - import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.SharedConfig; @@ -127,11 +125,12 @@ public class AdjustPanLayoutHelper { onPanTranslationUpdate(-y, v, isKeyboardVisible); }); animationInProgress = true; + int selectedAccount = UserConfig.selectedAccount; animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animationInProgress = false; - NotificationCenter.getInstance(UserConfig.selectedAccount).onAnimationFinish(notificationsIndex); + NotificationCenter.getInstance(selectedAccount).onAnimationFinish(notificationsIndex); animator = null; setViewHeight(ViewGroup.LayoutParams.MATCH_PARENT); viewsToHeightSet.clear(); @@ -144,7 +143,7 @@ public class AdjustPanLayoutHelper { animator.setDuration(220); animator.setInterpolator(CubicBezierInterpolator.DEFAULT); - notificationsIndex = NotificationCenter.getInstance(UserConfig.selectedAccount).setAnimationInProgress(notificationsIndex, null); + notificationsIndex = NotificationCenter.getInstance(selectedAccount).setAnimationInProgress(notificationsIndex, null); animator.start(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java index 41814847f..d8a9ee13d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/AlertDialog.java @@ -83,6 +83,7 @@ public class AlertDialog extends Dialog implements Drawable.Callback { private CharSequence subtitle; private CharSequence message; private int topResId; + private View topView; private int topAnimationId; private int topHeight = 132; private Drawable topDrawable; @@ -270,6 +271,14 @@ public class AlertDialog extends Dialog implements Drawable.Callback { topImageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(topHeight), MeasureSpec.EXACTLY)); availableHeight -= topImageView.getMeasuredHeight() - AndroidUtilities.dp(8); } + if (topView != null) { + int w = width - AndroidUtilities.dp(16); + float scale = w / 936.0f; + int h = (int) (354 * scale); + topView.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); + topView.getLayoutParams().height = h; + availableHeight -= topView.getMeasuredHeight(); + } if (progressViewStyle == 0) { layoutParams = (LayoutParams) contentScrollView.getLayoutParams(); @@ -398,6 +407,9 @@ public class AlertDialog extends Dialog implements Drawable.Callback { topImageView.getBackground().setColorFilter(new PorterDuffColorFilter(topBackgroundColor, PorterDuff.Mode.SRC_IN)); topImageView.setPadding(0, 0, 0, 0); containerView.addView(topImageView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, topHeight, Gravity.LEFT | Gravity.TOP, -8, -8, 0, 0)); + } else if (topView != null) { + topView.setPadding(0, 0, 0, 0); + containerView.addView(topView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, topHeight, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); } if (title != null) { @@ -1107,6 +1119,11 @@ public class AlertDialog extends Dialog implements Drawable.Callback { return this; } + public Builder setTopView(View view) { + alertDialog.topView = view; + return this; + } + public Builder setTopAnimation(int resId, int backgroundColor) { alertDialog.topAnimationId = resId; alertDialog.topBackgroundColor = backgroundColor; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 60908f4d4..5abe3bdab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -42,6 +42,7 @@ import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; @@ -436,6 +437,10 @@ public class BaseFragment { } } + protected int getPreviewHeight() { + return LayoutHelper.MATCH_PARENT; + } + protected void onBecomeFullyHidden() { } 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 1698c88f4..9f15ded15 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -522,9 +522,6 @@ public class BottomSheet extends Dialog { float translation = 0; if (Build.VERSION.SDK_INT >= 29 && getAdditionalMandatoryOffsets() > 0) { float dist = containerView.getMeasuredHeight() - containerView.getTranslationY(); - if (currentSheetAnimationType == 1) { - dist *= 0.1f; - } translation = Math.max(0, bottomInset - dist); } int navBarHeight = drawNavigationBar ? bottomInset : 0; @@ -680,11 +677,6 @@ public class BottomSheet extends Dialog { } } - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - } - public void setAllowNestedScroll(boolean value) { allowNestedScroll = value; if (!allowNestedScroll) { @@ -1256,6 +1248,10 @@ public class BottomSheet extends Dialog { return this; } + public View getCustomView() { + return bottomSheet.customView; + } + public Builder setTitle(CharSequence title) { return setTitle(title, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java index bee51da2f..291b67a4a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -164,7 +164,7 @@ public class SimpleTextView extends View implements Drawable.Callback { } } - private boolean createLayout(int width) { + protected boolean createLayout(int width) { if (text != null) { try { if (leftDrawable != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java index b8479244e..6942fdf2d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -85,11 +85,18 @@ import org.telegram.ui.Cells.ThemesHorizontalListCell; import org.telegram.ui.Components.AudioVisualizerDrawable; import org.telegram.ui.Components.BackgroundGradientDrawable; import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.MsgClockDrawable; import org.telegram.ui.Components.PathAnimator; +import org.telegram.ui.Components.PlayingGameDrawable; import org.telegram.ui.Components.RLottieDrawable; +import org.telegram.ui.Components.RecordStatusDrawable; +import org.telegram.ui.Components.RoundStatusDrawable; import org.telegram.ui.Components.ScamDrawable; +import org.telegram.ui.Components.SendingFileDrawable; +import org.telegram.ui.Components.StatusDrawable; import org.telegram.ui.Components.SvgHelper; import org.telegram.ui.Components.ThemeEditorView; +import org.telegram.ui.Components.TypingDotsDrawable; import java.io.File; import java.io.FileInputStream; @@ -108,6 +115,7 @@ import java.util.HashSet; import java.util.Locale; import tw.nekomimi.nekogram.NekoConfig; +import androidx.core.graphics.ColorUtils; public class Theme { @@ -222,6 +230,10 @@ public class Theme { isBottomNear = bottomNear; } + public int getTopY() { + return topY; + } + private int dp(float value) { if (currentType == TYPE_PREVIEW) { return (int) Math.ceil(3 * value); @@ -481,7 +493,7 @@ public class Theme { } } if (currentType == TYPE_MEDIA) { - if (currentType == TYPE_PREVIEW || paintToUse != null || topY + bounds.bottom - rad < currentBackgroundHeight) { + if (paintToUse != null || topY + bounds.bottom - rad < currentBackgroundHeight) { int radToUse = isBottomNear ? nearRad : rad; path.lineTo(bounds.right - padding, bounds.bottom - padding - radToUse); @@ -536,7 +548,7 @@ public class Theme { } } if (currentType == TYPE_MEDIA) { - if (currentType == TYPE_PREVIEW || paintToUse != null || topY + bounds.bottom - rad < currentBackgroundHeight) { + if (paintToUse != null || topY + bounds.bottom - rad < currentBackgroundHeight) { int radToUse = isBottomNear ? nearRad : rad; path.lineTo(bounds.left + padding, bounds.bottom - padding - radToUse); @@ -558,8 +570,9 @@ public class Theme { path.close(); canvas.drawPath(path, p); - if (gradientShader != null && isSelected) { - selectedPaint.setColor(getColor(key_chat_outBubbleGradientSelectedOverlay)); + if (gradientShader != null && isSelected && paintToUse == null) { + int color = getColor(key_chat_outBubbleGradientSelectedOverlay); + selectedPaint.setColor(ColorUtils.setAlphaComponent(color, (int) (Color.alpha(color) * alpha / 255f))); canvas.drawPath(path, selectedPaint); } } @@ -977,7 +990,7 @@ public class Theme { int subTextColor; int seekbarColor; if (useBlackText(myMessagesAccentColor, myMessagesGradientAccentColor)) { - textColor = 0xff000000; + textColor = 0xff212121; subTextColor = 0xff555555; seekbarColor = 0x4d000000; } else { @@ -1012,6 +1025,7 @@ public class Theme { currentColors.put(key_chat_outPreviewInstantSelectedText, textColor); currentColors.put(key_chat_outViews, textColor); + currentColors.put(key_chat_outViewsSelected, textColor); currentColors.put(key_chat_outAudioTitleText, textColor); currentColors.put(key_chat_outFileNameText, textColor); @@ -1978,6 +1992,7 @@ public class Theme { public static Paint dialogs_countPaint; public static Paint dialogs_errorPaint; public static Paint dialogs_countGrayPaint; + public static Paint dialogs_actionMessagePaint; public static TextPaint[] dialogs_namePaint; public static TextPaint[] dialogs_nameEncryptedPaint; public static TextPaint dialogs_searchNamePaint; @@ -2085,6 +2100,7 @@ public class Theme { public static MessageDrawable chat_msgInMediaSelectedDrawable; public static MessageDrawable chat_msgOutMediaDrawable; public static MessageDrawable chat_msgOutMediaSelectedDrawable; + private static StatusDrawable[] chat_status_drawables = new StatusDrawable[5]; public static PathAnimator playPauseAnimator; public static Drawable chat_msgOutCheckDrawable; @@ -2113,6 +2129,12 @@ public class Theme { public static Drawable chat_msgInRepliesSelectedDrawable; public static Drawable chat_msgOutRepliesDrawable; public static Drawable chat_msgOutRepliesSelectedDrawable; + public static Drawable chat_msgInPinnedDrawable; + public static Drawable chat_msgInPinnedSelectedDrawable; + public static Drawable chat_msgOutPinnedDrawable; + public static Drawable chat_msgOutPinnedSelectedDrawable; + public static Drawable chat_msgStickerPinnedDrawable; + public static Drawable chat_msgMediaPinnedDrawable; public static Drawable chat_msgMediaViewsDrawable; public static Drawable chat_msgMediaRepliesDrawable; public static Drawable chat_msgInMenuDrawable; @@ -3427,10 +3449,10 @@ public class Theme { defaultColors.put(key_chat_messagePanelVoiceDuration, 0xffffffff); defaultColors.put(key_chat_inlineResultIcon, 0xff5795cc); defaultColors.put(key_chat_topPanelBackground, 0xffffffff); - defaultColors.put(key_chat_topPanelClose, 0xff8c959a); + defaultColors.put(key_chat_topPanelClose, 0xff8b969b); defaultColors.put(key_chat_topPanelLine, 0xff6c9fd2); defaultColors.put(key_chat_topPanelTitle, 0xff3a8ccf); - defaultColors.put(key_chat_topPanelMessage, 0xff999999); + defaultColors.put(key_chat_topPanelMessage, 0xff878e91); defaultColors.put(key_chat_reportSpam, 0xffcf5957); defaultColors.put(key_chat_addContact, 0xff4a82b5); defaultColors.put(key_chat_inLoader, 0xff72b5e8); @@ -3524,7 +3546,7 @@ public class Theme { defaultColors.put(key_inappPlayerTitle, 0xff2f3438); defaultColors.put(key_inappPlayerBackground, 0xffffffff); defaultColors.put(key_inappPlayerPlayPause, 0xff62b0eb); - defaultColors.put(key_inappPlayerClose, 0xffa8a8a8); + defaultColors.put(key_inappPlayerClose, 0xff8b969b); defaultColors.put(key_returnToCallBackground, 0xff44a1e3); defaultColors.put(key_returnToCallText, 0xffffffff); @@ -4379,6 +4401,8 @@ public class Theme { eventType = 0; } else if (NekoConfig.eventType == 2 || (monthOfYear == 1 && dayOfMonth == 14)) { eventType = 1; + } else if (monthOfYear == 9 && dayOfMonth >= 30 || monthOfYear == 10 && dayOfMonth == 1 && hour < 12) { + eventType = 2; } return eventType; } @@ -6627,13 +6651,14 @@ public class Theme { dialogs_countPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dialogs_countGrayPaint = new Paint(Paint.ANTI_ALIAS_FLAG); dialogs_errorPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + dialogs_actionMessagePaint = new Paint(Paint.ANTI_ALIAS_FLAG); dialogs_lockDrawable = resources.getDrawable(R.drawable.list_secret); dialogs_checkDrawable = resources.getDrawable(R.drawable.list_check).mutate(); dialogs_playDrawable = resources.getDrawable(R.drawable.minithumb_play).mutate(); dialogs_checkReadDrawable = resources.getDrawable(R.drawable.list_check).mutate(); dialogs_halfCheckDrawable = resources.getDrawable(R.drawable.list_halfcheck); - dialogs_clockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); + dialogs_clockDrawable = new MsgClockDrawable(); dialogs_errorDrawable = resources.getDrawable(R.drawable.list_warning_sign); dialogs_reorderDrawable = resources.getDrawable(R.drawable.list_reorder).mutate(); dialogs_groupDrawable = resources.getDrawable(R.drawable.list_group); @@ -6680,6 +6705,7 @@ public class Theme { dialogs_archiveTextPaint.setColor(getColor(key_chats_archiveText)); dialogs_countPaint.setColor(getColor(key_chats_unreadCounter)); dialogs_countGrayPaint.setColor(getColor(key_chats_unreadCounterMuted)); + dialogs_actionMessagePaint.setColor(getColor(key_chats_actionMessage)); dialogs_errorPaint.setColor(getColor(key_chats_sentError)); dialogs_onlinePaint.setColor(getColor(key_windowBackgroundWhiteBlueText3)); dialogs_offlinePaint.setColor(getColor(key_windowBackgroundWhiteGrayText3)); @@ -6839,12 +6865,12 @@ public class Theme { chat_msgOutHalfCheckSelectedDrawable = resources.getDrawable(R.drawable.msg_halfcheck).mutate(); chat_msgMediaHalfCheckDrawable = resources.getDrawable(R.drawable.msg_halfcheck_s).mutate(); chat_msgStickerHalfCheckDrawable = resources.getDrawable(R.drawable.msg_halfcheck_s).mutate(); - chat_msgOutClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); - chat_msgOutSelectedClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); - chat_msgInClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); - chat_msgInSelectedClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); - chat_msgMediaClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); - chat_msgStickerClockDrawable = resources.getDrawable(R.drawable.deproko_baseline_clock_24).mutate(); + chat_msgOutClockDrawable = new MsgClockDrawable(); + chat_msgOutSelectedClockDrawable = new MsgClockDrawable(); + chat_msgInClockDrawable = new MsgClockDrawable(); + chat_msgInSelectedClockDrawable = new MsgClockDrawable(); + chat_msgMediaClockDrawable = new MsgClockDrawable(); + chat_msgStickerClockDrawable = new MsgClockDrawable(); chat_msgInViewsDrawable = resources.getDrawable(R.drawable.msg_views).mutate(); chat_msgInViewsSelectedDrawable = resources.getDrawable(R.drawable.msg_views).mutate(); chat_msgOutViewsDrawable = resources.getDrawable(R.drawable.msg_views).mutate(); @@ -6853,6 +6879,12 @@ public class Theme { chat_msgInRepliesSelectedDrawable = resources.getDrawable(R.drawable.msg_reply_small).mutate(); chat_msgOutRepliesDrawable = resources.getDrawable(R.drawable.msg_reply_small).mutate(); chat_msgOutRepliesSelectedDrawable = resources.getDrawable(R.drawable.msg_reply_small).mutate(); + chat_msgInPinnedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); + chat_msgInPinnedSelectedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); + chat_msgOutPinnedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); + chat_msgOutPinnedSelectedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); + chat_msgMediaPinnedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); + chat_msgStickerPinnedDrawable = resources.getDrawable(R.drawable.msg_pin_mini).mutate(); chat_msgMediaViewsDrawable = resources.getDrawable(R.drawable.msg_views).mutate(); chat_msgMediaRepliesDrawable = resources.getDrawable(R.drawable.msg_reply_small).mutate(); chat_msgStickerViewsDrawable = resources.getDrawable(R.drawable.msg_views).mutate(); @@ -7186,6 +7218,12 @@ public class Theme { setDrawableColorByKey(chat_msgInRepliesSelectedDrawable, key_chat_inViewsSelected); setDrawableColorByKey(chat_msgOutRepliesDrawable, key_chat_outViews); setDrawableColorByKey(chat_msgOutRepliesSelectedDrawable, key_chat_outViewsSelected); + setDrawableColorByKey(chat_msgInPinnedDrawable, key_chat_inViews); + setDrawableColorByKey(chat_msgInPinnedSelectedDrawable, key_chat_inViewsSelected); + setDrawableColorByKey(chat_msgOutPinnedDrawable, key_chat_outViews); + setDrawableColorByKey(chat_msgOutPinnedSelectedDrawable, key_chat_outViewsSelected); + setDrawableColorByKey(chat_msgMediaPinnedDrawable, key_chat_mediaViews); + setDrawableColorByKey(chat_msgStickerPinnedDrawable, key_chat_serviceText); setDrawableColorByKey(chat_msgMediaViewsDrawable, key_chat_mediaViews); setDrawableColorByKey(chat_msgMediaRepliesDrawable, key_chat_mediaViews); setDrawableColorByKey(chat_msgInMenuDrawable, key_chat_inMenu); @@ -7223,6 +7261,10 @@ public class Theme { setDrawableColorByKey(calllog_msgCallDownRedDrawable, key_calls_callReceivedRedIcon); setDrawableColorByKey(calllog_msgCallDownGreenDrawable, key_calls_callReceivedGreenIcon); + for (int i = 0; i < chat_status_drawables.length; i++) { + setDrawableColorByKey(chat_status_drawables[i], key_chats_actionMessage); + } + for (int a = 0; a < 2; a++) { setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][0], getColor(key_chat_outLoader), false); setCombinedDrawableColor(chat_fileMiniStatesDrawable[a][0], getColor(key_chat_outMediaIcon), true); @@ -7601,7 +7643,11 @@ public class Theme { if (drawable == null) { return; } - if (drawable instanceof ShapeDrawable) { + if (drawable instanceof StatusDrawable) { + ((StatusDrawable) drawable).setColor(color); + } else if (drawable instanceof MsgClockDrawable) { + ((MsgClockDrawable) drawable).setColor(color); + } else if (drawable instanceof ShapeDrawable) { ((ShapeDrawable) drawable).getPaint().setColor(color); } else if (drawable instanceof ScamDrawable) { ((ScamDrawable) drawable).setColor(color); @@ -7620,20 +7666,16 @@ public class Theme { public static void setEmojiDrawableColor(Drawable drawable, int color, boolean selected) { if (drawable instanceof StateListDrawable) { try { + Drawable state; if (selected) { - Drawable state = getStateDrawable(drawable, 0); - if (state instanceof ShapeDrawable) { - ((ShapeDrawable) state).getPaint().setColor(color); - } else { - state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); - } + state = getStateDrawable(drawable, 0); } else { - Drawable state = getStateDrawable(drawable, 1); - if (state instanceof ShapeDrawable) { - ((ShapeDrawable) state).getPaint().setColor(color); - } else { - state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); - } + state = getStateDrawable(drawable, 1); + } + if (state instanceof ShapeDrawable) { + ((ShapeDrawable) state).getPaint().setColor(color); + } else { + state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); } } catch (Throwable ignore) { @@ -7658,26 +7700,22 @@ public class Theme { public static void setSelectorDrawableColor(Drawable drawable, int color, boolean selected) { if (drawable instanceof StateListDrawable) { try { + Drawable state; if (selected) { - Drawable state = getStateDrawable(drawable, 0); + state = getStateDrawable(drawable, 0); if (state instanceof ShapeDrawable) { ((ShapeDrawable) state).getPaint().setColor(color); } else { state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); } state = getStateDrawable(drawable, 1); - if (state instanceof ShapeDrawable) { - ((ShapeDrawable) state).getPaint().setColor(color); - } else { - state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); - } } else { - Drawable state = getStateDrawable(drawable, 2); - if (state instanceof ShapeDrawable) { - ((ShapeDrawable) state).getPaint().setColor(color); - } else { - state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); - } + state = getStateDrawable(drawable, 2); + } + if (state instanceof ShapeDrawable) { + ((ShapeDrawable) state).getPaint().setColor(color); + } else { + state.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); } } catch (Throwable ignore) { @@ -8114,4 +8152,35 @@ public class Theme { } return animatedOutVisualizerDrawables.get(messageObject); } + + public static StatusDrawable getChatStatusDrawable(int type) { + if (type < 0 || type > 4) { + return null; + } + StatusDrawable statusDrawable = chat_status_drawables[type]; + if (statusDrawable != null) { + return statusDrawable; + } + switch (type) { + case 0: + chat_status_drawables[0] = new TypingDotsDrawable(true); + break; + case 1: + chat_status_drawables[1] = new RecordStatusDrawable(true); + break; + case 2: + chat_status_drawables[2] = new SendingFileDrawable(true); + break; + case 3: + chat_status_drawables[3] = new PlayingGameDrawable(true); + break; + case 4: + chat_status_drawables[4] = new RoundStatusDrawable(true); + break; + } + statusDrawable = chat_status_drawables[type]; + statusDrawable.start(); + statusDrawable.setColor(getColor(key_chats_actionMessage)); + return statusDrawable; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java index 27ef51ffa..9ccd2bbb9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ThemeDescription.java @@ -353,6 +353,10 @@ public class ThemeDescription { } } else if (viewToInvalidate instanceof ContextProgressView) { ((ContextProgressView) viewToInvalidate).updateColors(); + } else if (viewToInvalidate instanceof SeekBarView) { + if ((changeFlags & FLAG_PROGRESSBAR) != 0) { + ((SeekBarView) viewToInvalidate).setOuterColor(color); + } } if ((changeFlags & FLAG_TEXTCOLOR) != 0) { if ((changeFlags & FLAG_CHECKTAG) == 0 || checkTag(currentKey, viewToInvalidate)) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index d8796e1f4..0afbf785c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -50,6 +50,8 @@ import org.telegram.ui.Cells.HintDialogCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Components.FlickerLoadingView; +import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.FilteredSearchView; @@ -58,6 +60,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private Context mContext; @@ -179,7 +184,6 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @Override public void onDataSetChanged(int searchId) { waitingResponseCount--; - Log.d("kek", "data set change " + waitingResponseCount); lastGlobalSearchId = searchId; if (lastLocalSearchId != searchId) { searchResult.clear(); @@ -340,7 +344,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } } notifyDataSetChanged(); - if (delegate != null && req.offset_id == 0) { + if (delegate != null) { delegate.searchStateChanged(waitingResponseCount > 0, true); delegate.runResultsEnterAnimation(); } @@ -567,7 +571,6 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { private void updateSearchResults(final ArrayList result, final ArrayList names, final ArrayList encUsers, final int searchId) { AndroidUtilities.runOnUIThread(() -> { waitingResponseCount--; - Log.d("kek", "update local search " + waitingResponseCount); if (searchId != lastSearchId) { return; } @@ -678,6 +681,8 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { notifyDataSetChanged(); if (needMessagesSearch != 2 && delegate != null) { delegate.searchStateChanged(true, false); + } else { + waitingResponseCount--; } Utilities.searchQueue.postRunnable(searchRunnable = () -> { @@ -862,7 +867,10 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { view = new DialogCell(mContext, false, true); break; case 3: - view = new LoadingCell(mContext); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); + flickerLoadingView.setIsSingleCell(true); + view = flickerLoadingView; break; case 4: view = new HashtagSearchCell(mContext); @@ -872,7 +880,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { @Override public boolean onInterceptTouchEvent(MotionEvent e) { if (getParent() != null && getParent().getParent() != null) { - getParent().getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1)); + getParent().getParent().requestDisallowInterceptTouchEvent(canScrollHorizontally(-1) || canScrollHorizontally(1)); } return super.onInterceptTouchEvent(e); } @@ -987,7 +995,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } if (nameSearch != null && (index = AndroidUtilities.indexOfIgnoreCase(nameSearch, foundUserName)) != -1) { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(nameSearch); - spannableStringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)), index, index + foundUserName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spannableStringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_windowBackgroundWhiteBlueText4), index, index + foundUserName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); name = spannableStringBuilder; } else if (un != null) { if (foundUserName.startsWith("@")) { @@ -1004,7 +1012,7 @@ public class DialogsSearchAdapter extends RecyclerListView.SelectionAdapter { } else { index++; } - spannableStringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)), index, index + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spannableStringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_windowBackgroundWhiteBlueText4), index, index + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } username = spannableStringBuilder; } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java index 2553cfd2e..0b01b32d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java @@ -18,6 +18,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.LinearLayoutManager; @@ -84,6 +85,14 @@ public class FiltersView extends RecyclerListView { public boolean supportsPredictiveItemAnimations() { return false; } + + @Override + public void onInitializeAccessibilityNodeInfo(@NonNull Recycler recycler, @NonNull State state, @NonNull AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(recycler, state, info); + if (!isEnabled()) { + info.setVisibleToUser(false); + } + } }; layoutManager.setOrientation(HORIZONTAL); setLayoutManager(layoutManager); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java index 3e560474a..8755fadc9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/LocationActivityAdapter.java @@ -99,6 +99,12 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca } } + public void updateLiveLocationCell() { + if (shareLiveLocationPotistion > 0) { + notifyItemChanged(shareLiveLocationPotistion); + } + } + public void updateLiveLocations() { if (!currentLiveLocations.isEmpty()) { notifyItemRangeChanged(2, currentLiveLocations.size(), new Object()); @@ -115,7 +121,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca currentLiveLocations = new ArrayList<>(liveLocations); int uid = UserConfig.getInstance(currentAccount).getClientUserId(); for (int a = 0; a < currentLiveLocations.size(); a++) { - if (currentLiveLocations.get(a).id == uid) { + if (currentLiveLocations.get(a).id == uid || currentLiveLocations.get(a).object.out) { currentLiveLocations.remove(a); break; } @@ -212,7 +218,9 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca @Override public int getItemCount() { - if (locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW) { + if (locationType == LocationActivity.LOCATION_TYPE_LIVE_VIEW) { + return 2; + } else if (locationType == LocationActivity.LOCATION_TYPE_GROUP_VIEW) { return 2; } else if (locationType == LocationActivity.LOCATION_TYPE_GROUP) { return 2; @@ -221,13 +229,13 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca } else if (locationType == 2) { return 2 + currentLiveLocations.size(); } else { - if (searching || !searching && places.isEmpty()) { + if (searching || places.isEmpty()) { return (locationType != 0 ? 6 : 5) + (needEmptyView ? 1 : 0); } if (locationType == 1) { - return 5 + places.size() + (places.isEmpty() ? 0 : 1) + (needEmptyView ? 1 : 0); + return 6 + places.size() + (needEmptyView ? 1 : 0); } else { - return 4 + places.size() + (places.isEmpty() ? 0 : 1) + (needEmptyView ? 1 : 0); + return 5 + places.size() + (needEmptyView ? 1 : 0); } } } @@ -336,7 +344,9 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca break; case 7: SharingLiveLocationCell locationCell = (SharingLiveLocationCell) holder.itemView; - if (chatLocation != null) { + if (locationType == LocationActivity.LOCATION_TYPE_LIVE_VIEW) { + locationCell.setDialog(currentMessageObject, gpsLocation); + } else if (chatLocation != null) { locationCell.setDialog(dialogId, chatLocation); } else if (currentMessageObject != null && position == 1) { locationCell.setDialog(currentMessageObject, gpsLocation); @@ -392,6 +402,9 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca if (position == 0) { return 0; } + if (locationType == LocationActivity.LOCATION_TYPE_LIVE_VIEW) { + return 7; + } if (needEmptyView && position == getItemCount() - 1) { return 10; } @@ -436,7 +449,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca return 9; } else if (position == 4) { return 2; - } else if (searching || !searching && places.isEmpty()) { + } else if (searching || places.isEmpty()) { return 4; } else if (position == places.size() + 5) { return 5; @@ -448,7 +461,7 @@ public class LocationActivityAdapter extends BaseLocationAdapter implements Loca return 9; } else if (position == 3) { return 2; - } else if (searching || !searching && places.isEmpty()) { + } else if (searching || places.isEmpty()) { return 4; } else if (position == places.size() + 4) { return 5; 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 19922056f..c0f14236e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -48,6 +48,7 @@ import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import androidx.recyclerview.widget.RecyclerView; @@ -65,8 +66,8 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { private long dialog_id; private TLRPC.ChatFull info; private SearchAdapterHelper searchAdapterHelper; - private ArrayList searchResultUsernames; - private SparseArray searchResultUsernamesMap; + private ArrayList searchResultUsernames; + private SparseArray searchResultUsernamesMap; private Runnable searchGlobalRunnable; private ArrayList searchResultHashtags; private ArrayList searchResultCommands; @@ -683,9 +684,9 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } final String usernameString = result.toString().toLowerCase(); boolean hasSpace = usernameString.indexOf(' ') >= 0; - ArrayList newResult = new ArrayList<>(); + ArrayList newResult = new ArrayList<>(); final SparseArray newResultsHashMap = new SparseArray<>(); - final SparseArray newMap = new SparseArray<>(); + final SparseArray newMap = new SparseArray<>(); ArrayList inlineBots = MediaDataController.getInstance(currentAccount).inlineBots; if (!usernameOnly && needBotContext && dogPostion == 0 && !inlineBots.isEmpty()) { int count = 0; @@ -706,61 +707,96 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } } final TLRPC.Chat chat; + int threadId; if (parentFragment != null) { chat = parentFragment.getCurrentChat(); + threadId = parentFragment.getThreadId(); } else if (info != null) { chat = messagesController.getChat(info.id); + threadId = 0; } else { chat = null; + threadId = 0; } if (chat != null && info != null && info.participants != null && (!ChatObject.isChannel(chat) || chat.megagroup)) { - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant chatParticipant = info.participants.participants.get(a); - TLRPC.User user = messagesController.getUser(chatParticipant.user_id); - if (user == null || !usernameOnly && UserObject.isUserSelf(user) || newResultsHashMap.indexOfKey(user.id) >= 0) { - continue; - } - if (usernameString.length() == 0) { - if (!user.deleted) { - newResult.add(user); + for (int a = -1; a < info.participants.participants.size(); a++) { + String username; + String firstName; + String lastName; + TLObject object; + int id; + if (a == -1) { + if (chat == null) { + continue; } + if (usernameString.length() == 0) { + newResult.add(chat); + continue; + } + firstName = chat.title; + lastName = null; + username = chat.username; + object = chat; + id = -chat.id; } else { - if (user.username != null && user.username.length() > 0 && user.username.toLowerCase().startsWith(usernameString)) { - newResult.add(user); - newMap.put(user.id, user); - } else { - if (user.first_name != null && user.first_name.length() > 0 && user.first_name.toLowerCase().startsWith(usernameString)) { + TLRPC.ChatParticipant chatParticipant = info.participants.participants.get(a); + TLRPC.User user = messagesController.getUser(chatParticipant.user_id); + if (user == null || !usernameOnly && UserObject.isUserSelf(user) || newResultsHashMap.indexOfKey(user.id) >= 0) { + continue; + } + if (usernameString.length() == 0) { + if (!user.deleted) { newResult.add(user); - newMap.put(user.id, user); - } else if (user.last_name != null && user.last_name.length() > 0 && user.last_name.toLowerCase().startsWith(usernameString)) { - newResult.add(user); - newMap.put(user.id, user); - } else if (hasSpace && ContactsController.formatName(user.first_name, user.last_name).toLowerCase().startsWith(usernameString)) { - newResult.add(user); - newMap.put(user.id, user); + continue; } } + firstName = user.first_name; + lastName = user.last_name; + username = user.username; + object = user; + id = user.id; + } + if (!TextUtils.isEmpty(username) && username.toLowerCase().startsWith(usernameString) || + !TextUtils.isEmpty(firstName) && firstName.toLowerCase().startsWith(usernameString) || + !TextUtils.isEmpty(lastName) && lastName.toLowerCase().startsWith(usernameString) || + hasSpace && ContactsController.formatName(firstName, lastName).toLowerCase().startsWith(usernameString)) { + newResult.add(object); + newMap.put(id, object); } } } - Collections.sort(newResult, (lhs, rhs) -> { - if (newMap.indexOfKey(lhs.id) >= 0 && newMap.indexOfKey(rhs.id) >= 0) { + Collections.sort(newResult, new Comparator() { + + private int getId(TLObject object) { + if (object instanceof TLRPC.User) { + return ((TLRPC.User) object).id; + } else { + return -((TLRPC.Chat) object).id; + } + } + + @Override + public int compare(TLObject lhs, TLObject rhs) { + int id1 = getId(lhs); + int id2 = getId(rhs); + if (newMap.indexOfKey(id1) >= 0 && newMap.indexOfKey(id2) >= 0) { + return 0; + } else if (newMap.indexOfKey(id1) >= 0) { + return -1; + } else if (newMap.indexOfKey(id2) >= 0) { + return 1; + } + int lhsNum = users.indexOf(id1); + int rhsNum = users.indexOf(id2); + if (lhsNum != -1 && rhsNum != -1) { + return lhsNum < rhsNum ? -1 : (lhsNum == rhsNum ? 0 : 1); + } else if (lhsNum != -1 && rhsNum == -1) { + return -1; + } else if (lhsNum == -1 && rhsNum != -1) { + return 1; + } return 0; - } else if (newMap.indexOfKey(lhs.id) >= 0) { - return -1; - } else if (newMap.indexOfKey(rhs.id) >= 0) { - return 1; } - int lhsNum = users.indexOf(lhs.id); - int rhsNum = users.indexOf(rhs.id); - if (lhsNum != -1 && rhsNum != -1) { - return lhsNum < rhsNum ? -1 : (lhsNum == rhsNum ? 0 : 1); - } else if (lhsNum != -1 && rhsNum == -1) { - return -1; - } else if (lhsNum == -1 && rhsNum != -1) { - return 1; - } - return 0; }); searchResultHashtags = null; searchResultCommands = null; @@ -787,9 +823,14 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { req.channel = MessagesController.getInputChannel(chat); req.limit = 20; req.offset = 0; - TLRPC.TL_channelParticipantsSearch channelParticipantsSearch = new TLRPC.TL_channelParticipantsSearch(); - channelParticipantsSearch.q = usernameString; - req.filter = channelParticipantsSearch; + TLRPC.TL_channelParticipantsMentions channelParticipantsMentions = new TLRPC.TL_channelParticipantsMentions(); + channelParticipantsMentions.flags |= 1; + channelParticipantsMentions.q = usernameString; + if (threadId != 0) { + channelParticipantsMentions.flags |= 2; + channelParticipantsMentions.top_msg_id = threadId; + } + req.filter = channelParticipantsMentions; final int currentReqId = ++channelLastReqId; channelReqId = ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { if (channelReqId != 0 && currentReqId == channelLastReqId && searchResultUsernamesMap != null && searchResultUsernames != null) { @@ -887,7 +928,7 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } } - private void showUsersResult(ArrayList newResult, SparseArray newMap, boolean notify) { + private void showUsersResult(ArrayList newResult, SparseArray newMap, boolean notify) { searchResultUsernames = newResult; searchResultUsernamesMap = newMap; if (cancelDelayRunnable != null) { @@ -1080,7 +1121,12 @@ public class MentionsAdapter extends RecyclerListView.SelectionAdapter { } } else { if (searchResultUsernames != null) { - ((MentionCell) holder.itemView).setUser(searchResultUsernames.get(position)); + TLObject object = searchResultUsernames.get(position); + if (object instanceof TLRPC.User) { + ((MentionCell) holder.itemView).setUser((TLRPC.User) object); + } else if (object instanceof TLRPC.Chat) { + ((MentionCell) holder.itemView).setChat((TLRPC.Chat) object); + } } else if (searchResultHashtags != null) { ((MentionCell) holder.itemView).setText(searchResultHashtags.get(position)); } else if (searchResultSuggestions != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java index 1a1603ade..84123386f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java @@ -11,7 +11,6 @@ package org.telegram.ui.Adapters; import android.content.Context; import android.text.SpannableStringBuilder; import android.text.Spanned; -import android.text.style.ForegroundColorSpan; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; @@ -33,6 +32,7 @@ import org.telegram.ui.Cells.GraySectionCell; import org.telegram.ui.Cells.ProfileSearchCell; import org.telegram.ui.Cells.TextCell; import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.RecyclerListView; import java.util.ArrayList; @@ -315,7 +315,7 @@ public class SearchAdapter extends RecyclerListView.SelectionAdapter { } } else if (position > searchResult.size() && un != null) { String foundUserName = searchAdapterHelper.getLastFoundUsername(); - if (foundUserName.startsWith("@")) { + if (foundUserName != null && foundUserName.startsWith("@")) { foundUserName = foundUserName.substring(1); } try { @@ -323,14 +323,14 @@ public class SearchAdapter extends RecyclerListView.SelectionAdapter { SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); spannableStringBuilder.append("@"); spannableStringBuilder.append(un); - if ((index = AndroidUtilities.indexOfIgnoreCase(un, foundUserName)) != -1) { + if (foundUserName != null && (index = AndroidUtilities.indexOfIgnoreCase(un, foundUserName)) != -1) { int len = foundUserName.length(); if (index == 0) { len++; } else { index++; } - spannableStringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_windowBackgroundWhiteBlueText4)), index, index + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + spannableStringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_windowBackgroundWhiteBlueText4), index, index + len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } username = spannableStringBuilder; } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java index a66be29ea..89470453e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapterHelper.java @@ -463,14 +463,16 @@ public class SearchAdapterHelper { state.step(); } state.dispose(); - MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); - if (arrayList.size() >= 100) { - MessagesStorage.getInstance(currentAccount).getDatabase().beginTransaction(); + if (arrayList.size() > 100) { + state = MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE id = ?"); for (int a = 100; a < arrayList.size(); a++) { - MessagesStorage.getInstance(currentAccount).getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE id = '" + arrayList.get(a).hashtag + "'").stepThis().dispose(); + state.requery(); + state.bindString(1, arrayList.get(a).hashtag); + state.step(); } - MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); + state.dispose(); } + MessagesStorage.getInstance(currentAccount).getDatabase().commitTransaction(); } catch (Exception e) { FileLog.e(e); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersSearchAdapter.java index 16f5c339e..3a8fca04c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/StickersSearchAdapter.java @@ -1,6 +1,7 @@ package org.telegram.ui.Adapters; import android.content.Context; +import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.text.TextUtils; @@ -339,11 +340,13 @@ public class StickersSearchAdapter extends RecyclerListView.SelectionAdapter { View view = null; switch (viewType) { case 0: - view = new StickerEmojiCell(context) { + StickerEmojiCell stickerEmojiCell = new StickerEmojiCell(context) { public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(82), MeasureSpec.EXACTLY)); } }; + view = stickerEmojiCell; + stickerEmojiCell.getImageView().setLayerNum(3); break; case 1: view = new EmptyCell(context); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java index b0894e148..b99d60fcd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ArticleViewer.java @@ -868,7 +868,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg } public boolean handleTouchEvent(MotionEvent event) { - if (!closeAnimationInProgress && fullscreenVideoContainer.getVisibility() != VISIBLE && !textSelectionHelper.isSelectionMode()) { + if (pageSwitchAnimation == null && !closeAnimationInProgress && fullscreenVideoContainer.getVisibility() != VISIBLE && !textSelectionHelper.isSelectionMode()) { if (event != null && event.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking) { startedTrackingPointerId = event.getPointerId(0); maybeStartTracking = true; @@ -3662,7 +3662,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg windowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW - 1; - windowLayoutParams.softInputMode = SharedConfig.smoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; + windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; if (Build.VERSION.SDK_INT >= 21) { windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | @@ -4048,10 +4048,6 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return false; } - if (messageObject != null) { - webpage = messageObject.messageOwner.media.webpage; - } - String anchor = null; if (messageObject != null) { webpage = messageObject.messageOwner.media.webpage; @@ -4122,7 +4118,7 @@ public class ArticleViewer implements NotificationCenter.NotificationCenterDeleg return; } - if (!pagesStack.isEmpty() && pagesStack.get(0) == webPageFinal && webPage.cached_page != null) { + if (!pagesStack.isEmpty() && pagesStack.get(0) == webPageFinal) { if (messageObject != null) { messageObject.messageOwner.media.webpage = webPage; TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); 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 401d58a1f..f54e44a98 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -95,9 +95,7 @@ public class AboutLinkCell extends FrameLayout { } oldText = text; stringBuilder = new SpannableStringBuilder(oldText); - if (parseLinks) { - MessageObject.addLinks(false, stringBuilder, false, false); - } + MessageObject.addLinks(false, stringBuilder, false, false, !parseLinks); Emoji.replaceEmoji(stringBuilder, Theme.profile_aboutTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); if (TextUtils.isEmpty(value)) { valueTextView.setVisibility(GONE); 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 0d1ec2e30..39205a7d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -8,10 +8,13 @@ package org.telegram.ui.Cells; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.Keyframe; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; @@ -93,6 +96,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ChatActivity; import org.telegram.ui.Components.AnimatedFileDrawable; +import org.telegram.ui.Components.AnimatedNumberLayout; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AudioVisualizerDrawable; import org.telegram.ui.Components.AvatarDrawable; @@ -112,6 +116,7 @@ import org.telegram.ui.Components.RoundVideoPlayingDrawable; import org.telegram.ui.Components.SeekBar; import org.telegram.ui.Components.SeekBarAccessibilityDelegate; import org.telegram.ui.Components.SeekBarWaveform; +import org.telegram.ui.Components.SlotsDrawable; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.TextStyleSpan; import org.telegram.ui.Components.TimerParticles; @@ -265,22 +270,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private int angle; private float progressAlpha; private long lastUpdateTime; - private TransitionParams transitionParams = new TransitionParams(); - - private class TransitionParams { - int transitionType; - int fromX; - int fromY; - int fromWidth; - int fromHeight; - - void saveState() { - fromX = x; - fromY = y; - fromWidth = width; - fromHeight = height; - } - } } public static class PollButton { @@ -346,9 +335,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float lastTouchX; private float lastTouchY; - private boolean drawPhotoCheckBox; + private boolean drawMediaCheckBox; private boolean drawSelectionBackground; - private CheckBoxBase photoCheckBox; + private CheckBoxBase mediaCheckBox; private CheckBoxBase checkBox; private boolean checkBoxVisible; private boolean checkBoxAnimationInProgress; @@ -440,6 +429,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private String currentUrl; private WebFile currentWebFile; + private WebFile lastWebFile; private boolean addedForTest; private boolean hasEmbed; @@ -578,14 +568,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate public boolean isMegagroup; public boolean isThreadChat; public boolean hasDiscussion; + public boolean isPinned; + private boolean wasPinned; public int linkedChatId; - public boolean hasLinkedChat; public boolean isRepliesChat; + public boolean isPinnedChat; private boolean isPressed; private boolean forwardName; private boolean isHighlighted; private boolean isHighlightedAnimated; private int highlightProgress; + private float currentSelectedBackgroundAlpha; private long lastHighlightProgressTime; private boolean mediaBackground; private boolean isMedia; @@ -627,11 +620,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private AvatarDrawable[] commentAvatarDrawables; private boolean[] commentAvatarImagesVisible; private StaticLayout commentLayout; + private AnimatedNumberLayout commentNumberLayout; + private boolean drawCommentNumber; private int commentArrowX; private int commentUnreadX; private boolean commentDrawUnread; private int commentWidth; + private int commentX; private int totalCommentWidth; + private int commentNumberWidth; private boolean drawCommentButton; private Rect commentButtonRect = new Rect(); private boolean commentButtonPressed; @@ -674,7 +671,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private StaticLayout[] forwardedNameLayout = new StaticLayout[2]; private int forwardedNameWidth; private boolean drawForwardedName; - private int forwardNameX; + private float forwardNameX; private int forwardNameY; private float[] forwardNameOffsetX = new float[2]; @@ -737,6 +734,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } }; + private int animateToStatusDrawableParams; + private int animateFromStatusDrawableParams; + private float statusDrawableProgress; + private boolean statusDrawableAnimationInProgress; + private ValueAnimator statusDrawableAnimator; + + private int overideShouldDrawTimeOnMedia; + private Runnable invalidateRunnable = new Runnable() { @Override public void run() { @@ -768,6 +773,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate avatarImage.setRoundRadius(AndroidUtilities.dp(21)); avatarDrawable = new AvatarDrawable(); replyImageReceiver = new ImageReceiver(this); + replyImageReceiver.setRoundRadius(AndroidUtilities.dp(2)); locationImageReceiver = new ImageReceiver(this); locationImageReceiver.setRoundRadius(AndroidUtilities.dp(26.1f)); TAG = DownloadController.getInstance(currentAccount).generateObserverTag(); @@ -837,7 +843,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate for (int a = 0; a < pollCheckBox.length; a++) { pollCheckBox[a] = new CheckBoxBase(this, 20); pollCheckBox[a].setDrawUnchecked(false); - pollCheckBox[a].setDrawBackgroundAsArc(9); + pollCheckBox[a].setBackgroundType(9); } } @@ -952,7 +958,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate isMono = true; } boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore) { @@ -1055,7 +1061,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate link = buffer.getSpans(off, off, URLSpanMono.class); } boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore) { @@ -1116,7 +1122,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Spannable buffer = (Spannable) currentMessageObject.linkDescription; ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore) { @@ -1197,7 +1203,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Spannable buffer = (Spannable) currentMessageObject.linkDescription; ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + if (link.length == 0 || link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { ignore = true; } if (!ignore) { @@ -1580,6 +1586,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private boolean checkOtherButtonMotionEvent(MotionEvent event) { + if ((documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) && currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { + return false; + } boolean allow = currentMessageObject.type == 16; if (!allow) { allow = !(documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && currentMessageObject.type != 12 && documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_VIDEO && documentAttachType != DOCUMENT_ATTACH_TYPE_GIF && currentMessageObject.type != 8 || hasGamePreview || hasInvoicePreview); @@ -2016,16 +2025,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (currentChat != null) { int id; + TLRPC.Chat chat = currentChat; if (currentMessageObject.messageOwner.fwd_from != null) { if ((currentMessageObject.messageOwner.fwd_from.flags & 16) != 0) { id = currentMessageObject.messageOwner.fwd_from.saved_from_msg_id; } else { id = currentMessageObject.messageOwner.fwd_from.channel_post; + chat = currentForwardChannel; } } else { id = 0; } - delegate.didPressChannelAvatar(this, currentChat, id, lastTouchX, lastTouchY); + delegate.didPressChannelAvatar(this, chat != null ? chat : currentChat, id, lastTouchX, lastTouchY); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -2156,7 +2167,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return false; } - if (currentMessageObject.hasValidGroupId() && currentMessagesGroup != null) { + if (currentMessageObject.hasValidGroupId() && currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { ViewGroup parent = (ViewGroup) getParent(); for (int i = 0; i < parent.getChildCount(); i++) { View v = parent.getChildAt(i); @@ -2603,7 +2614,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return true; } - if (currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && newPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id)) { + if (currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id)) { return true; } @@ -2620,22 +2631,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return true; } - String newNameString = null; - if (drawName && isChat && !currentMessageObject.isOutOwner()) { - if (currentUser != null) { - newNameString = UserObject.getUserName(currentUser); - } else if (currentChat != null) { - newNameString = currentChat.title; - } - } - - if (currentNameString == null && newNameString != null || currentNameString != null && newNameString == null || currentNameString != null && newNameString != null && !currentNameString.equals(newNameString)) { + String newNameString = isNeedAuthorName() ? getAuthorName() : null; + if (currentNameString == null && newNameString != null || currentNameString != null && newNameString == null || currentNameString != null && !currentNameString.equals(newNameString)) { return true; } if (drawForwardedName && currentMessageObject.needDrawForwarded()) { newNameString = currentMessageObject.getForwardedName(); - return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && newNameString != null && !currentForwardNameString.equals(newNameString); + return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && !currentForwardNameString.equals(newNameString); } return false; } @@ -2652,7 +2655,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentUser != null && currentUser.id == 0) { return (int) avatarImage.getCenterX(); } - return forwardNameX + forwardNameCenterX; + return (int) (forwardNameX + forwardNameCenterX); } public TLRPC.User getCurrentUser() { @@ -2669,8 +2672,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (checkBox != null) { checkBox.onDetachedFromWindow(); } - if (photoCheckBox != null) { - photoCheckBox.onDetachedFromWindow(); + if (mediaCheckBox != null) { + mediaCheckBox.onDetachedFromWindow(); } if (pollCheckBox != null) { for (int a = 0; a < pollCheckBox.length; a++) { @@ -2708,13 +2711,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (MediaController.getInstance().isPlayingMessage(currentMessageObject)) { Theme.getCurrentAudiVisualizerDrawable().setParentView(null); } + + if (statusDrawableAnimator != null) { + statusDrawableAnimator.removeAllListeners(); + statusDrawableAnimator.cancel(); + } + statusDrawableAnimationInProgress = false; } @Override public void onAttachedToWindow() { super.onAttachedToWindow(); + if (currentMessageObject != null) { + currentMessageObject.animateComments = false; + } if (messageObjectToSet != null) { + messageObjectToSet.animateComments = false; setMessageContent(messageObjectToSet, groupedMessagesToSet, bottomNearToSet, topNearToSet); messageObjectToSet = null; groupedMessagesToSet = null; @@ -2722,8 +2735,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (checkBox != null) { checkBox.onAttachedToWindow(); } - if (photoCheckBox != null) { - photoCheckBox.onAttachedToWindow(); + if (mediaCheckBox != null) { + mediaCheckBox.onAttachedToWindow(); } if (pollCheckBox != null) { for (int a = 0; a < pollCheckBox.length; a++) { @@ -2790,7 +2803,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate boolean messageChanged = currentMessageObject != messageObject || messageObject.forceUpdate; boolean dataChanged = currentMessageObject != null && currentMessageObject.getId() == messageObject.getId() && lastSendState == MessageObject.MESSAGE_SEND_STATE_EDITING && messageObject.isSent() || currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet) - || lastPostAuthor != messageObject.messageOwner.post_author; + || lastPostAuthor != messageObject.messageOwner.post_author + || wasPinned != isPinned; boolean groupChanged = groupedMessages != currentMessagesGroup; boolean pollChanged = false; if (drawCommentButton || drawSideButton == 3 && !((hasDiscussion && messageObject.isLinkedToChat(linkedChatId) || isRepliesChat) && (currentPosition == null || currentPosition.siblingHeights == null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0 || currentPosition.siblingHeights != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0))) { @@ -2846,6 +2860,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate transChanged = true; } if (messageChanged || dataChanged || groupChanged || pollChanged || isPhotoDataChanged(messageObject) || pinnedBottom != bottomNear || pinnedTop != topNear || transChanged) { + wasPinned = isPinned; pinnedBottom = bottomNear; pinnedTop = topNear; currentMessageObject = messageObject; @@ -2863,8 +2878,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentMessagesGroup = null; currentPosition = null; } - drawPinnedTop = pinnedTop && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); - drawPinnedBottom = pinnedBottom && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0); + if (currentMessagesGroup == null || currentMessagesGroup.isDocuments) { + drawPinnedTop = pinnedTop; + drawPinnedBottom = pinnedBottom; + } else { + drawPinnedTop = pinnedTop && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); + drawPinnedBottom = pinnedBottom && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0); + } + photoImage.setCrossfadeWithOldImage(false); photoImage.setCrossfadeDuration(ImageReceiver.DEFAULT_CROSSFADE_DURATION); lastSendState = messageObject.messageOwner.send_state; @@ -2885,8 +2906,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate drawVideoSize = false; canStreamVideo = false; animatingNoSound = 0; - drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) ? 1 : 0; - if (drawSideButton == 1 && messageObject.messageOwner.fwd_from != null && !messageObject.isOutOwner() && messageObject.messageOwner.fwd_from.saved_from_peer != null && messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId()) { + drawSideButton = !isRepliesChat && checkNeedDrawShareButton(messageObject) && (currentPosition == null || currentPosition.last) ? 1 : 0; + if (isPinnedChat || drawSideButton == 1 && messageObject.messageOwner.fwd_from != null && !messageObject.isOutOwner() && messageObject.messageOwner.fwd_from.saved_from_peer != null && messageObject.getDialogId() == UserConfig.getInstance(currentAccount).getClientUserId()) { drawSideButton = 2; } replyNameLayout = null; @@ -2915,7 +2936,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate resetPressedLink(-1); messageObject.forceUpdate = false; drawPhotoImage = false; - drawPhotoCheckBox = false; + drawMediaCheckBox = false; hasLinkPreview = false; hasOldCaptionPreview = false; hasGamePreview = false; @@ -2968,8 +2989,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate ImageLoader.getInstance().removeTestWebFile(currentUrl); } addedForTest = false; - currentUrl = null; - currentWebFile = null; photoNotSet = false; drawBackground = true; drawName = false; @@ -3035,7 +3054,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (isRepliesChat) { comment = LocaleController.getString("ViewInChat", R.string.ViewInChat); } else { - comment = commentCount == 0 ? LocaleController.getString("LeaveAComment", R.string.LeaveAComment) : LocaleController.formatPluralString("CommentsCount", commentCount); + if (LocaleController.isRTL) { + comment = commentCount == 0 ? LocaleController.getString("LeaveAComment", R.string.LeaveAComment) : LocaleController.formatPluralString("CommentsCount", commentCount); + } else { + comment = commentCount == 0 ? LocaleController.getString("LeaveAComment", R.string.LeaveAComment) : LocaleController.getPluralString("CommentsNoNumber", commentCount); + } ArrayList recentRepliers = getRecentRepliers(); if (commentCount != 0 && recentRepliers != null && !recentRepliers.isEmpty()) { createCommentUI(); @@ -3076,6 +3099,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } commentWidth = totalCommentWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(comment)); commentLayout = new StaticLayout(comment, Theme.chat_replyNamePaint, commentWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (commentCount != 0 && !LocaleController.isRTL) { + drawCommentNumber = true; + if (commentNumberLayout == null) { + commentNumberLayout = new AnimatedNumberLayout(this, Theme.chat_replyNamePaint); + commentNumberLayout.setNumber(commentCount, false); + } else { + commentNumberLayout.setNumber(commentCount, messageObject.animateComments); + } + messageObject.animateComments = false; + commentNumberWidth = commentNumberLayout.getWidth(); + totalCommentWidth += commentNumberWidth + AndroidUtilities.dp(4); + } else { + drawCommentNumber = false; + if (commentNumberLayout != null) { + commentNumberLayout.setNumber(1, false); + } + } totalCommentWidth += AndroidUtilities.dp(70 + avatarsOffset); } else { if (!isRepliesChat && commentCount > 0) { @@ -3085,10 +3125,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { commentLayout = null; } + drawCommentNumber = false; drawSideButton = isRepliesChat ? 2 : 3; } } else { commentLayout = null; + drawCommentNumber = false; } if (messageObject.type == 0) { @@ -3108,7 +3150,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); } - drawName = messageObject.messageOwner.peer_id.channel_id != 0 && (!messageObject.isOutOwner() || messageObject.isMegagroup()); + drawName = isPinnedChat || messageObject.messageOwner.peer_id.channel_id != 0 && (!messageObject.isOutOwner() || messageObject.isMegagroup()); } availableTimeWidth = maxWidth; @@ -3124,7 +3166,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate hasGamePreview = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame && messageObject.messageOwner.media.game instanceof TLRPC.TL_game; hasInvoicePreview = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaInvoice; - hasLinkPreview = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage; + hasLinkPreview = !messageObject.isRestrictedMessage && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage; drawInstantView = hasLinkPreview && messageObject.messageOwner.media.webpage.cached_page != null; hasEmbed = hasLinkPreview && !TextUtils.isEmpty(messageObject.messageOwner.media.webpage.embed_url) && !messageObject.isGif(); boolean slideshow = false; @@ -3553,13 +3595,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoParentObject = document; documentAttach = document; documentAttachType = DOCUMENT_ATTACH_TYPE_ROUND; - } else if (MessageObject.isGifDocument(document)) { + } else if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId())) { if (!messageObject.isGame() && !SharedConfig.autoplayGifs) { messageObject.gifState = 1; } photoImage.setAllowStartAnimation(messageObject.gifState != 1); currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 90); - photoParentObject = document; + if (currentPhotoObject != null) { + photoParentObject = document; + } else if (photo != null) { + currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photo.sizes, 90); + photoParentObject = photo; + } if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { for (int a = 0; a < document.attributes.size(); a++) { TLRPC.DocumentAttribute attribute = document.attributes.get(a); @@ -3894,7 +3941,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setRoundRadius(AndroidUtilities.roundMessageSize / 2); canChangeRadius = false; autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); - } else if (MessageObject.isGifDocument(document)) { + } else if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId())) { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } String filter = currentPhotoObject instanceof TLRPC.TL_photoStrippedSize || "s".equals(currentPhotoObject.type) ? currentPhotoFilterThumb : currentPhotoFilter; @@ -4147,7 +4194,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate namesOffset -= AndroidUtilities.dp(1); } } else if (messageObject.type == 14) { - drawName = messageObject.isFromGroup() && messageObject.isMegagroup(); + drawName = messageObject.isFromGroup() && messageObject.isMegagroup() && (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0); if (AndroidUtilities.isTablet()) { backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(drawAvatar ? 102 : 50), AndroidUtilities.dp(270)); } else { @@ -4159,6 +4206,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate setMessageObjectInternal(messageObject); totalHeight = AndroidUtilities.dp(82) + namesOffset; + if (currentPosition != null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { + if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { + totalHeight -= AndroidUtilities.dp(6); + mediaOffsetY -= AndroidUtilities.dp(6); + } + if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + totalHeight -= AndroidUtilities.dp(6); + } + } if (drawPinnedTop) { namesOffset -= AndroidUtilities.dp(1); } @@ -4525,7 +4581,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (maxTextWidth > 0) { + if (maxTextWidth > 0 && currentPosition == null) { backgroundWidth = maxTextWidth; maxWidth = maxTextWidth - AndroidUtilities.dp(31); } @@ -4540,16 +4596,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (docTitleLayout != null && docTitleLayout.getLineCount() > 1) { photoHeight += (docTitleLayout.getLineCount() - 1) * AndroidUtilities.dp(16); } - } - - if (!drawPhotoImage && TextUtils.isEmpty(messageObject.caption) && infoLayout != null) { - int lineCount = infoLayout.getLineCount(); - measureTime(messageObject); - int timeLeft = backgroundWidth - AndroidUtilities.dp(40 + 18 + 56 + 8) - infoWidth; - if (timeLeft < timeWidth) { - photoHeight += AndroidUtilities.dp(12); - } else if (lineCount == 1) { - photoHeight += AndroidUtilities.dp(4); + if (TextUtils.isEmpty(messageObject.caption) && infoLayout != null) { + int lineCount = infoLayout.getLineCount(); + measureTime(messageObject); + int timeLeft = backgroundWidth - AndroidUtilities.dp(40 + 18 + 56 + 8) - infoWidth; + if (timeLeft < timeWidth) { + photoHeight += AndroidUtilities.dp(12); + } else if (lineCount == 1) { + photoHeight += AndroidUtilities.dp(4); + } } } } else if (messageObject.type == 4) { //geo @@ -4594,6 +4649,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate double y = Math.round(offset - rad * Math.log((1 + Math.sin(lat * Math.PI / 180.0)) / (1 - Math.sin(lat * Math.PI / 180.0))) / 2) - (AndroidUtilities.dp(10.3f) << (21 - 15)); lat = (Math.PI / 2.0 - 2 * Math.atan(Math.exp((y - offset) / rad))) * 180.0 / Math.PI; currentUrl = AndroidUtilities.formapMapUrl(isSecretChat, lat, lon, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), false, 15); + lastWebFile = currentWebFile; currentWebFile = WebFile.createWithGeoPoint(lat, lon, point.access_hash, (int) (photoWidth / AndroidUtilities.density), (int) (photoHeight / AndroidUtilities.density), 15, Math.min(2, (int) Math.ceil(AndroidUtilities.density))); if (!(locationExpired = isCurrentLocationTimeExpired(messageObject))) { @@ -4696,7 +4752,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate photoImage.setImage(null, null, null, null, messageObject, 0); } else if (currentMapProvider == 2) { if (currentWebFile != null) { - photoImage.setImage(ImageLocation.getForWebFile(currentWebFile), null, null, null, messageObject, 0); + ImageLocation lastLocation = lastWebFile == null ? null : ImageLocation.getForWebFile(lastWebFile); + photoImage.setImage(ImageLocation.getForWebFile(currentWebFile), null, lastLocation, null, null, messageObject, 0); } } else { if (currentMapProvider == 3 || currentMapProvider == 4) { @@ -4754,13 +4811,18 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageObject.isDice()) { filter = String.format(Locale.US, "%d_%d_dice_%s_%s", w, h, messageObject.getDiceEmoji(), messageObject.toString()); photoImage.setAutoRepeat(2); - TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(currentMessageObject.getDiceEmoji()); + String emoji = currentMessageObject.getDiceEmoji(); + TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(emoji); if (stickerSet != null) { if (stickerSet.documents.size() > 0) { int value = currentMessageObject.getDiceValue(); if (value <= 0) { TLRPC.Document document = stickerSet.documents.get(0); - currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); + if ("\uD83C\uDFB0".equals(emoji)) { + currentPhotoObjectThumb = null; + } else { + currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 40); + } photoParentObject = document; } } @@ -5148,7 +5210,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - int minWidth = (int) (Theme.chat_infoPaint.measureText("100%") + AndroidUtilities.dp(48) + timeWidth); + int minWidth = (int) (Theme.chat_infoPaint.measureText("100%") + AndroidUtilities.dp(100/*48*/)/* + timeWidth*/); if (currentMessagesGroup == null && (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) && photoWidth < minWidth) { photoWidth = minWidth; backgroundWidth = photoWidth + AndroidUtilities.dp(8); @@ -5264,11 +5326,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } boolean autoDownload = false; TLRPC.Document document = messageObject.getDocument(); - if (MessageObject.isGifDocument(document) || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { + if (MessageObject.isGifDocument(document, messageObject.hasValidGroupId()) || messageObject.type == MessageObject.TYPE_ROUND_VIDEO) { autoDownload = DownloadController.getInstance(currentAccount).canDownloadMedia(currentMessageObject); } TLRPC.VideoSize videoSize = MessageObject.getDocumentVideoThumb(document); - if (((MessageObject.isGifDocument(document) && messageObject.videoEditedInfo == null) || (!messageObject.isSending() && !messageObject.isEditing())) && (localFile != 0 || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || autoDownload)) { + if (((MessageObject.isGifDocument(document, messageObject.hasValidGroupId()) && messageObject.videoEditedInfo == null) || (!messageObject.isSending() && !messageObject.isEditing())) && (localFile != 0 || FileLoader.getInstance(currentAccount).isLoadingFile(fileName) || autoDownload)) { if (localFile != 1 && !messageObject.needDrawBluredPreview() && (localFile != 0 || messageObject.canStreamVideo() && autoDownload)) { autoPlayingMedia = true; if (!messageIdChanged) { @@ -5324,7 +5386,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate namesOffset += AndroidUtilities.dp(7); } totalHeight = photoHeight + AndroidUtilities.dp(14) + namesOffset + additionHeight; - if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && !currentMessageObject.isDocument()) { totalHeight -= AndroidUtilities.dp(3); } if (currentMessageObject.isDice()) { @@ -5333,7 +5395,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } int additionalTop = 0; - if (currentPosition != null) { + if (currentPosition != null && !currentMessageObject.isDocument()) { photoWidth += getAdditionalWidthForPosition(currentPosition); if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { photoHeight += AndroidUtilities.dp(4); @@ -5356,11 +5418,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate y = AndroidUtilities.dp(5); totalHeight -= AndroidUtilities.dp(4); } + if (currentPosition != null && currentMessagesGroup.isDocuments && currentMessagesGroup.messages.size() > 1) { + if ((currentPosition.flags & MessageObject.POSITION_FLAG_TOP) == 0) { + totalHeight -= AndroidUtilities.dp(drawPhotoImage ? 3 : 6); + mediaOffsetY -= AndroidUtilities.dp(drawPhotoImage ? 3 : 6); + y -= AndroidUtilities.dp(drawPhotoImage ? 3 : 6); + } + if ((currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + totalHeight -= AndroidUtilities.dp(drawPhotoImage ? 3 : 6); + } + } photoImage.setImageCoords(0, y + namesOffset + additionalTop, photoWidth, photoHeight); invalidate(); } - if (currentPosition == null && !messageObject.isAnyKindOfSticker() && addedCaptionHeight == 0) { + if ((currentPosition == null || currentMessageObject.isMusic() || currentMessageObject.isDocument()) && !messageObject.isAnyKindOfSticker() && addedCaptionHeight == 0) { if (!messageObject.isRestrictedMessage && captionLayout == null && messageObject.caption != null) { try { currentCaption = messageObject.caption; @@ -5384,14 +5456,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int width = backgroundWidth - AndroidUtilities.dp(31); if (captionLayout != null && captionLayout.getLineCount() > 0) { captionWidth = width; - int timeWidthTotal = timeWidth + (messageObject.isOutOwner() ? AndroidUtilities.dp(20) : 0) + getExtraTimeX(); captionHeight = captionLayout.getHeight(); totalHeight += captionHeight + AndroidUtilities.dp(9); - float lastLineWidth = captionLayout.getLineWidth(captionLayout.getLineCount() - 1) + captionLayout.getLineLeft(captionLayout.getLineCount() - 1); - if (width - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) { - totalHeight += AndroidUtilities.dp(14); - captionHeight += AndroidUtilities.dp(14); - captionNewLine = 2; + if (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + int timeWidthTotal = timeWidth + (messageObject.isOutOwner() ? AndroidUtilities.dp(20) : 0) + getExtraTimeX(); + float lastLineWidth = captionLayout.getLineWidth(captionLayout.getLineCount() - 1) + captionLayout.getLineLeft(captionLayout.getLineCount() - 1); + if (width - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) { + totalHeight += AndroidUtilities.dp(14); + captionHeight += AndroidUtilities.dp(14); + captionNewLine = 2; + } } } } catch (Exception e) { @@ -5399,7 +5473,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } - if (captionLayout == null && widthBeforeNewTimeLine != -1 && availableTimeWidth - widthBeforeNewTimeLine < timeWidth) { + if ((currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) && captionLayout == null && widthBeforeNewTimeLine != -1 && availableTimeWidth - widthBeforeNewTimeLine < timeWidth) { totalHeight += AndroidUtilities.dp(14); } @@ -5460,7 +5534,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate botButtonsByPosition.clear(); botButtonsLayout = null; } - if (currentPosition == null && (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup || messageObject.messageOwner.reactions != null && !messageObject.messageOwner.reactions.results.isEmpty())) { + if (!messageObject.isRestrictedMessage && currentPosition == null && (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup || messageObject.messageOwner.reactions != null && !messageObject.messageOwner.reactions.results.isEmpty())) { int rows; if (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) { @@ -5638,7 +5712,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (hasLinkPreview || hasGamePreview || hasInvoicePreview) { tl = tr = bl = br = minRad; } - if (forwardedNameLayout[0] != null || replyNameLayout != null) { + if (forwardedNameLayout[0] != null || replyNameLayout != null || drawNameLayout) { tl = tr = minRad; } if (captionLayout != null || drawCommentButton) { @@ -5682,10 +5756,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } if (messageIdChanged) { + currentUrl = null; + currentWebFile = null; + lastWebFile = null; loadingProgressLayout = null; animatingLoadingProgressProgress = 0; lastLoadingSizeTotal = 0; selectedBackgroundProgress = 0f; + if (statusDrawableAnimator != null) { + statusDrawableAnimator.removeAllListeners(); + statusDrawableAnimator.cancel(); + } + transitionParams.lastStatusDrawableParams = -1; + statusDrawableAnimationInProgress = false; } if (isBlockedUserMessage()) { totalHeight = 0; @@ -5859,6 +5942,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } + @Override + public void invalidate(int l, int t, int r, int b) { + if (currentMessageObject == null) { + return; + } + super.invalidate(l, t, r, b); + if (invalidatesParent) { + if (getParent() != null) { + View parent = (View) getParent(); + parent.invalidate((int) getX() + l, (int) getY() + t, (int) getX() + r, (int) getY() + b); + } + } + } + public boolean isHighlightedAnimated() { return isHighlightedAnimated; } @@ -6029,7 +6126,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate docTitleLayout = new StaticLayout(str, Theme.chat_infoPaint, docTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } return 0; - } else if (MessageObject.isGifDocument(documentAttach)) { + } else if (MessageObject.isGifDocument(documentAttach, messageObject.hasValidGroupId())) { documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; if (!messageObject.needDrawBluredPreview()) { @@ -6043,13 +6140,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } return 0; } else { - drawPhotoImage = documentAttach.mime_type != null && documentAttach.mime_type.toLowerCase().startsWith("image/") || MessageObject.isDocumentHasThumb(documentAttach); + drawPhotoImage = documentAttach.mime_type != null && (documentAttach.mime_type.toLowerCase().startsWith("image/") || documentAttach.mime_type.toLowerCase().startsWith("video/mp4")) || MessageObject.isDocumentHasThumb(documentAttach); if (!drawPhotoImage) { maxWidth += AndroidUtilities.dp(30); } documentAttachType = DOCUMENT_ATTACH_TYPE_DOCUMENT; String name = FileLoader.getDocumentFileName(documentAttach); - if (name == null || name.length() == 0) { + if (name.length() == 0) { name = LocaleController.getString("AttachDocument", R.string.AttachDocument); } docTitleLayout = StaticLayoutEx.createStaticLayout(name, Theme.chat_docNamePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.MIDDLE, maxWidth, 2, false); @@ -6759,12 +6856,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate needNewVisiblePart = false; } - int buttonX = this.buttonX; - int buttonY = this.buttonY; + float buttonX = this.buttonX; + float buttonY = this.buttonY; if (transitionParams.animateButton) { - buttonX = (int) (transitionParams.animateFromButtonX * (1f - transitionParams.animateChangeProgress) + this.buttonX * (transitionParams.animateChangeProgress)); - buttonY = (int) (transitionParams.animateFromButtonY * (1f - transitionParams.animateChangeProgress) + this.buttonY * (transitionParams.animateChangeProgress)); - radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(44), buttonY + AndroidUtilities.dp(44)); + buttonX = transitionParams.animateFromButtonX * (1f - transitionParams.animateChangeProgress) + this.buttonX * (transitionParams.animateChangeProgress); + buttonY = (transitionParams.animateFromButtonY * (1f - transitionParams.animateChangeProgress) + this.buttonY * (transitionParams.animateChangeProgress)); + radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + AndroidUtilities.dp(44), (int) buttonY + AndroidUtilities.dp(44)); } if (transitionParams.animateBackgroundBoundsInner && documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { int backgroundWidth = this.backgroundWidth - transitionParams.deltaLeft + transitionParams.deltaRight; @@ -6802,6 +6899,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate videoRadialProgress.setProgressColor(Theme.getColor(Theme.key_chat_mediaProgress)); boolean imageDrawn = false; + radialProgress.setCircleCrossfadeColor(null, 0.0f, 1.0f); if (currentMessageObject.type == 0) { if (currentMessageObject.isOutOwner()) { textX = getCurrentBackgroundLeft() + AndroidUtilities.dp(11) + getExtraTextX(); @@ -6917,7 +7015,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int size = AndroidUtilities.dp(48); buttonX = this.buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); - radialProgress.setProgressRect(buttonX, buttonY, buttonX + size, buttonY + size); + radialProgress.setProgressRect((int) buttonX, (int ) buttonY, (int) buttonX + size, (int) buttonY + size); } imageDrawn = photoImage.draw(canvas); } @@ -6993,7 +7091,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int size = AndroidUtilities.dp(48); buttonX = this.buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); buttonY = this.buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); - radialProgress.setProgressRect(buttonX, buttonY, buttonX + size, buttonY + size); + radialProgress.setProgressRect((int) buttonX, (int) buttonY, (int) buttonX + size, (int) buttonY + size); } } if (currentMessageObject.isRoundVideo() && MediaController.getInstance().isPlayingMessage(currentMessageObject) && MediaController.getInstance().isVideoDrawingReady() && canvas.isHardwareAccelerated()) { @@ -7127,23 +7225,25 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate setDrawableBounds(iconDrawable, rect.centerX() - iconDrawable.getIntrinsicWidth() / 2, rect.centerY() - iconDrawable.getIntrinsicHeight() / 2); iconDrawable.draw(canvas); } - drawPhotoCheckBox = photoCheckBox != null && (checkBoxVisible || photoCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && currentMessagesGroup != null; - if (drawPhotoCheckBox && (photoCheckBox.isChecked() || photoCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && (!textIsSelectionMode())) { - Theme.chat_replyLinePaint.setColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected)); - rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); - int[] rad = photoImage.getRoundRadius(); - rectPath.reset(); - for (int a = 0; a < rad.length; a++) { - radii[a * 2] = radii[a * 2 + 1] = rad[a]; + drawMediaCheckBox = mediaCheckBox != null && (checkBoxVisible || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && currentMessagesGroup != null; + if (drawMediaCheckBox && (mediaCheckBox.isChecked() || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && (!textIsSelectionMode())) { + if (!currentMessagesGroup.isDocuments) { + Theme.chat_replyLinePaint.setColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected)); + rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX2(), photoImage.getImageY2()); + int[] rad = photoImage.getRoundRadius(); + rectPath.reset(); + for (int a = 0; a < rad.length; a++) { + radii[a * 2] = radii[a * 2 + 1] = rad[a]; + } + rectPath.addRoundRect(rect, radii, Path.Direction.CW); + rectPath.close(); + canvas.drawPath(rectPath, Theme.chat_replyLinePaint); } - rectPath.addRoundRect(rect, radii, Path.Direction.CW); - rectPath.close(); - canvas.drawPath(rectPath, Theme.chat_replyLinePaint); - photoImage.setSideClip(AndroidUtilities.dp(14) * photoCheckBox.getProgress()); + photoImage.setSideClip(AndroidUtilities.dp(14) * mediaCheckBox.getProgress()); if (checkBoxAnimationInProgress) { - photoCheckBox.setBackgroundAlpha(checkBoxAnimationProgress); + mediaCheckBox.setBackgroundAlpha(checkBoxAnimationProgress); } else { - photoCheckBox.setBackgroundAlpha(checkBoxVisible ? 1.0f : photoCheckBox.getProgress()); + mediaCheckBox.setBackgroundAlpha(checkBoxVisible ? 1.0f : mediaCheckBox.getProgress()); } } else { photoImage.setSideClip(0); @@ -7178,8 +7278,26 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } + } else { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + drawMediaCheckBox = mediaCheckBox != null && (checkBoxVisible || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress) && currentMessagesGroup != null; + if (drawMediaCheckBox) { + radialProgress.setCircleCrossfadeColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText, checkBoxAnimationProgress, 1.0f - mediaCheckBox.getProgress()); + } + if (drawMediaCheckBox && !textIsSelectionMode() && (mediaCheckBox.isChecked() || mediaCheckBox.getProgress() != 0 || checkBoxAnimationInProgress)) { + if (checkBoxAnimationInProgress) { + mediaCheckBox.setBackgroundAlpha(checkBoxAnimationProgress); + if (radialProgress.getMiniIcon() == MediaActionDrawable.ICON_NONE) { + radialProgress.setMiniIconScale(checkBoxAnimationProgress); + } + } else { + mediaCheckBox.setBackgroundAlpha(checkBoxVisible ? 1.0f : mediaCheckBox.getProgress()); + } + } else if (mediaCheckBox != null) { + mediaCheckBox.setBackgroundAlpha(1.0f); + } + } } - if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { if (photoImage.getVisible() && !hasGamePreview && !currentMessageObject.needDrawBluredPreview()) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); @@ -7271,14 +7389,22 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate durationLayout.draw(canvas); canvas.restore(); - Drawable menuDrawable; - if (currentMessageObject.isOutOwner()) { - menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgOutMenuSelectedDrawable : Theme.chat_msgOutMenuDrawable; - } else { - menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; + if (shouldDrawMenuDrawable()) { + Drawable menuDrawable; + if (currentMessageObject.isOutOwner()) { + menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgOutMenuSelectedDrawable : Theme.chat_msgOutMenuDrawable; + } else { + menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; + } + setDrawableBounds(menuDrawable, otherX = (int) buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = (int) buttonY - AndroidUtilities.dp(2)); + if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { + menuDrawable.setAlpha((int) (255 * transitionParams.animateChangeProgress)); + } + menuDrawable.draw(canvas); + if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { + menuDrawable.setAlpha(255); + } } - setDrawableBounds(menuDrawable, otherX = buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = buttonY - AndroidUtilities.dp(2)); - menuDrawable.draw(canvas); } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { if (currentMessageObject.isOutOwner()) { Theme.chat_audioTimePaint.setColor(Theme.getColor(isDrawSelectionBackground() ? Theme.key_chat_outAudioDurationSelectedText : Theme.key_chat_outAudioDurationText)); @@ -7332,7 +7458,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (captionLayout != null) { updateCaptionLayout(); } - if (currentPosition == null && !transitionParams.transformGroupToSingleMessage) { + if ((currentPosition == null || currentMessagesGroup != null && currentMessagesGroup.isDocuments) && !transitionParams.transformGroupToSingleMessage) { drawCaptionLayout(canvas, false, 1f); } @@ -7397,7 +7523,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate menuDrawable = isDrawSelectionBackground() ? Theme.chat_msgInMenuSelectedDrawable : Theme.chat_msgInMenuDrawable; } - int x; + float x; int titleY; int subtitleY; if (drawPhotoImage) { @@ -7445,10 +7571,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } } else { - setDrawableBounds(menuDrawable, otherX = buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = buttonY - AndroidUtilities.dp(2)); + setDrawableBounds(menuDrawable, otherX = (int) buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = (int) buttonY - AndroidUtilities.dp(2)); x = buttonX + AndroidUtilities.dp(53); - titleY = buttonY + AndroidUtilities.dp(4); - subtitleY = buttonY + AndroidUtilities.dp(27); + titleY = (int) buttonY + AndroidUtilities.dp(4); + subtitleY = (int) buttonY + AndroidUtilities.dp(27); if (docTitleLayout != null && docTitleLayout.getLineCount() > 1) { subtitleY += (docTitleLayout.getLineCount() - 1) * AndroidUtilities.dp(16) + AndroidUtilities.dp(2); } @@ -7460,7 +7586,15 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate videoRadialProgress.setProgressColor(Theme.getColor(isDrawSelectionBackground() || videoButtonPressed != 0 ? Theme.key_chat_inAudioSelectedProgress : Theme.key_chat_inAudioProgress)); } } - menuDrawable.draw(canvas); + if (shouldDrawMenuDrawable()) { + if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { + menuDrawable.setAlpha((int) (255 * transitionParams.animateChangeProgress)); + } + menuDrawable.draw(canvas); + if (transitionParams.animateChangeProgress != 1f && transitionParams.animateShouldDrawMenuDrawable) { + menuDrawable.setAlpha(255); + } + } try { if (docTitleLayout != null) { @@ -7500,6 +7634,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate transitionParams.recordDrawingState(); } + private boolean shouldDrawMenuDrawable() { + return currentMessagesGroup == null || (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0; + } + private void drawBotButtons(Canvas canvas, ArrayList botButtons, float alpha) { int addX; if (currentMessageObject.isOutOwner()) { @@ -7544,7 +7682,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) { boolean drawProgress = (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonGame || button.button instanceof TLRPC.TL_keyboardButtonBuy || button.button instanceof TLRPC.TL_keyboardButtonUrlAuth) && SendMessagesHelper.getInstance(currentAccount).isSendingCallback(currentMessageObject, button.button) || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation && SendMessagesHelper.getInstance(currentAccount).isSendingCurrentLocation(currentMessageObject, button.button); - if (drawProgress || !drawProgress && button.progressAlpha != 0) { + if (drawProgress || button.progressAlpha != 0) { Theme.chat_botProgressPaint.setAlpha(Math.min(255, (int) (button.progressAlpha * 255))); int x = button.x + button.width - AndroidUtilities.dp(9 + 3) + addX; rect.set(x, y + AndroidUtilities.dp(4), x + AndroidUtilities.dp(8), y + AndroidUtilities.dp(8 + 4)); @@ -7676,7 +7814,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate captionY -= AndroidUtilities.dp(shouldDrawTimeOnMedia() ? 41.3f : 43); } } else { - captionX = backgroundDrawableLeft + AndroidUtilities.dp(currentMessageObject.isOutOwner() || mediaBackground || !mediaBackground && drawPinnedBottom ? 11 : 17) + captionOffsetX; + captionX = backgroundDrawableLeft + AndroidUtilities.dp(currentMessageObject.isOutOwner() || mediaBackground || drawPinnedBottom ? 11 : 17) + captionOffsetX; captionY = totalHeight - captionHeight - AndroidUtilities.dp(drawPinnedTop ? 9 : 10); if (drawCommentButton && drawSideButton != 3) { captionY -= AndroidUtilities.dp(shouldDrawTimeOnMedia() ? 41.3f : 43); @@ -7742,7 +7880,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return MediaActionDrawable.ICON_CANCEL; } else if (buttonState == 2) { return MediaActionDrawable.ICON_PLAY; - } else if (buttonState == 3) { + } else { return autoPlayingMedia ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_PLAY; } } else if (buttonState == -1) { @@ -7785,7 +7923,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } return maxWidth - backgroundWidth - AndroidUtilities.dp(57); } - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { int dWidth; if (AndroidUtilities.isTablet()) { dWidth = AndroidUtilities.getMinTabletSide(); @@ -7873,11 +8011,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate DownloadController.getInstance(currentAccount).addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); wasSending = true; buttonState = 4; - radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); + boolean sending = SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId()); + if (currentPosition != null && sending && buttonState == 4) { + drawRadialCheckBackground = true; + getIconForCurrentState(); + radialProgress.setIcon(MediaActionDrawable.ICON_CHECK, ifSame, animated); + } else { + radialProgress.setIcon(getIconForCurrentState(), ifSame, animated); + } + radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, animated); if (!fromBot) { long[] progress = ImageLoader.getInstance().getFileProgressSizes(currentMessageObject.messageOwner.attachPath); float loadingProgress = 0; - if (progress == null && SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId())) { + if (progress == null && sending) { loadingProgress = 1.0f; } else if (progress != null) { loadingProgress = DownloadController.getProgress(progress); @@ -7891,12 +8037,13 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CANCEL_NOPROFRESS, ifSame, false); radialProgress.setProgress(0, false); + radialProgress.setMiniIcon(MediaActionDrawable.ICON_NONE, ifSame, false); } } else { if (hasMiniProgress != 0) { radialProgress.setMiniProgressBackgroundColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader)); boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); - if (!playing || playing && MediaController.getInstance().isMessagePaused()) { + if (!playing || MediaController.getInstance().isMessagePaused()) { buttonState = 0; } else { buttonState = 1; @@ -7926,7 +8073,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (fileExists) { DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); boolean playing = MediaController.getInstance().isPlayingMessage(currentMessageObject); - if (!playing || playing && MediaController.getInstance().isMessagePaused()) { + if (!playing || MediaController.getInstance().isMessagePaused()) { buttonState = 0; } else { buttonState = 1; @@ -7965,7 +8112,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); float setProgress = 0; if (!FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { - if (!currentMessageObject.loadingCancelled && (documentAttachType == 0 && autoDownload || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MessageObject.isGifDocument(documentAttach) && autoDownload)) { + if (!currentMessageObject.loadingCancelled && (documentAttachType == 0 && autoDownload || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) && autoDownload)) { buttonState = 1; } else { buttonState = 0; @@ -8173,7 +8320,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int mask = MessageObject.POSITION_FLAG_LEFT | MessageObject.POSITION_FLAG_RIGHT; fullWidth = (currentPosition.flags & mask) == mask; } - if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || MessageObject.isGifDocument(documentAttach) && autoDownload) && canStreamVideo && hasDocLayout && fullWidth) { + if ((documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || MessageObject.isGifDocument(documentAttach, currentMessageObject.hasValidGroupId()) && autoDownload) && canStreamVideo && hasDocLayout && fullWidth) { drawVideoImageButton = true; getIconForCurrentState(); radialProgress.setIcon(autoPlayingMedia || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF ? MediaActionDrawable.ICON_NONE : MediaActionDrawable.ICON_PLAY, ifSame, animated); @@ -8368,7 +8515,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate buttonState = -1; radialProgress.setIcon(getIconForCurrentState(), false, animated); } - } else if (buttonState == 3 || buttonState == 0 && drawVideoImageButton) { + } else if (buttonState == 3 || buttonState == 0) { if (hasMiniProgress == 2 && miniButtonState != 1) { miniButtonState = 1; radialProgress.setProgress(0, false); @@ -8378,7 +8525,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else if (buttonState == 4) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { if (currentMessageObject.isOut() && (currentMessageObject.isSending() || currentMessageObject.isEditing()) || currentMessageObject.isSendError()) { - if (delegate != null) { + if (delegate != null && radialProgress.getIcon() != MediaActionDrawable.ICON_CHECK) { delegate.didPressCancelSendButton(this); } } else { @@ -8480,35 +8627,48 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate String emoji = currentMessageObject.getDiceEmoji(); TLRPC.TL_messages_stickerSet stickerSet = MediaDataController.getInstance(currentAccount).getStickerSetByEmojiOrName(emoji); if (stickerSet != null) { - if (!lottieDrawable.hasBaseDice() && stickerSet.documents.size() > 0) { - TLRPC.Document document = stickerSet.documents.get(0); - File path = FileLoader.getPathToAttach(document, true); - if (lottieDrawable.setBaseDice(path)) { - DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); - } else { - String fileName = FileLoader.getAttachFileName(document); - DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); - FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, 1, 1); - } - } int value = currentMessageObject.getDiceValue(); - if (value >= 0 && value < stickerSet.documents.size()) { - if (!instant && currentMessageObject.isOut()) { - MessagesController.DiceFrameSuccess frameSuccess = MessagesController.getInstance(currentAccount).diceSuccess.get(emoji); - if (frameSuccess != null && frameSuccess.num == value) { - lottieDrawable.setOnFinishCallback(diceFinishCallback, frameSuccess.frame); + if ("\uD83C\uDFB0".equals(currentMessageObject.getDiceEmoji())) { + if (value >= 0 && value <= 64) { + ((SlotsDrawable) lottieDrawable).setDiceNumber(this, value, stickerSet, instant); + if (currentMessageObject.isOut()) { + lottieDrawable.setOnFinishCallback(diceFinishCallback, Integer.MAX_VALUE); + } + currentMessageObject.wasUnread = false; + } + if (!lottieDrawable.hasBaseDice() && stickerSet.documents.size() > 0) { + ((SlotsDrawable) lottieDrawable).setBaseDice(this, stickerSet); + } + } else { + if (!lottieDrawable.hasBaseDice() && stickerSet.documents.size() > 0) { + TLRPC.Document document = stickerSet.documents.get(0); + File path = FileLoader.getPathToAttach(document, true); + if (lottieDrawable.setBaseDice(path)) { + DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); + } else { + String fileName = FileLoader.getAttachFileName(document); + DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); + FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, 1, 1); } } - TLRPC.Document document = stickerSet.documents.get(Math.max(value, 0)); - File path = FileLoader.getPathToAttach(document, true); - if (lottieDrawable.setDiceNumber(path, instant)) { - DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); - } else { - String fileName = FileLoader.getAttachFileName(document); - DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); - FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, 1, 1); + if (value >= 0 && value < stickerSet.documents.size()) { + if (!instant && currentMessageObject.isOut()) { + MessagesController.DiceFrameSuccess frameSuccess = MessagesController.getInstance(currentAccount).diceSuccess.get(emoji); + if (frameSuccess != null && frameSuccess.num == value) { + lottieDrawable.setOnFinishCallback(diceFinishCallback, frameSuccess.frame); + } + } + TLRPC.Document document = stickerSet.documents.get(Math.max(value, 0)); + File path = FileLoader.getPathToAttach(document, true); + if (lottieDrawable.setDiceNumber(path, instant)) { + DownloadController.getInstance(currentAccount).removeLoadingFileObserver(this); + } else { + String fileName = FileLoader.getAttachFileName(document); + DownloadController.getInstance(currentAccount).addLoadingFileObserver(fileName, currentMessageObject, this); + FileLoader.getInstance(currentAccount).loadFile(document, stickerSet, 1, 1); + } + currentMessageObject.wasUnread = false; } - currentMessageObject.wasUnread = false; } } else { MediaDataController.getInstance(currentAccount).loadStickersByEmojiOrName(emoji, true, true); @@ -8566,7 +8726,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate radialProgress.setProgress(progress, true); if (uploadedSize == totalSize && currentPosition != null) { boolean sending = SendMessagesHelper.getInstance(currentAccount).isSendingMessage(currentMessageObject.getId()); - if (sending && buttonState == 1) { + if (sending && (buttonState == 1 || buttonState == 4 && documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC)) { drawRadialCheckBackground = true; getIconForCurrentState(); radialProgress.setIcon(MediaActionDrawable.ICON_CHECK, false, true); @@ -8697,12 +8857,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.isFromUser()) { author = MessagesController.getInstance(currentAccount).getUser(fromId); } + boolean hasReplies = messageObject.hasReplies(); if (messageObject.scheduled || messageObject.isLiveLocation() || messageObject.messageOwner.edit_hide || messageObject.getDialogId() == 777000 || messageObject.messageOwner.via_bot_id != 0 || messageObject.messageOwner.via_bot_name != null || author != null && author.bot) { edited = false; - } else if (currentPosition == null || currentMessagesGroup == null) { + } else if (currentPosition == null || currentMessagesGroup == null || currentMessagesGroup.messages.isEmpty()) { edited = (messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0 || messageObject.isEditing(); } else { edited = false; + hasReplies = currentMessagesGroup.messages.get(0).hasReplies(); for (int a = 0, size = currentMessagesGroup.messages.size(); a < size; a++) { MessageObject object = currentMessagesGroup.messages.get(a); if ((object.messageOwner.flags & TLRPC.MESSAGE_FLAG_EDITED) != 0 || object.isEditing()) { @@ -8734,13 +8896,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate viewsTextWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(currentViewsString)); timeWidth += viewsTextWidth + Theme.chat_msgInViewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); } - if (hasLinkedChat && isChat && isMegagroup && !isThreadChat && messageObject.hasReplies()) { + if (isChat && isMegagroup && !isThreadChat && hasReplies) { currentRepliesString = String.format("%s", LocaleController.formatShortNumber(getRepliesCount(), null)); repliesTextWidth = (int) Math.ceil(Theme.chat_timePaint.measureText(currentRepliesString)); timeWidth += repliesTextWidth + Theme.chat_msgInRepliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); } else { currentRepliesString = null; } + if (isPinned) { + timeWidth += Theme.chat_msgInPinnedDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3); + } if (messageObject.scheduled) { if (messageObject.isSendError()) { timeWidth += AndroidUtilities.dp(18); @@ -8785,9 +8950,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private boolean checkNeedDrawShareButton(MessageObject messageObject) { - if ((currentPosition != null && !currentPosition.last) || currentMessageObject.deleted) { + if (currentMessageObject.deleted) { return false; } + if (currentPosition != null) { + if (!currentMessagesGroup.isDocuments && !currentPosition.last) { + return false; + } + } return messageObject.needDrawShareButton(); } @@ -8895,9 +9065,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate viaWidth = (int) Math.ceil(Theme.chat_replyNamePaint.measureText(viaString, 0, viaString.length())); } - boolean authorName = (!pinnedTop || ChatObject.isChannel(currentChat) && !currentChat.megagroup) && drawName && isChat && (!currentMessageObject.isOutOwner() || currentMessageObject.isMegagroup() && currentMessageObject.isFromGroup()); + boolean needAuthorName = isNeedAuthorName(); boolean viaBot = (messageObject.messageOwner.fwd_from == null || messageObject.type == 14) && viaUsername != null; - if (!hasPsaHint && (authorName || viaBot)) { + if (!hasPsaHint && (needAuthorName || viaBot)) { drawNameLayout = true; nameWidth = getMaxNameWidth(); if (nameWidth < 0) { @@ -8926,14 +9096,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate adminWidth = 0; } - if (authorName) { - if (currentUser != null) { - currentNameString = UserObject.getUserName(currentUser); - } else if (currentChat != null) { - currentNameString = currentChat.title; - } else { - currentNameString = "DELETED"; - } + if (needAuthorName) { + currentNameString = getAuthorName(); } else { currentNameString = ""; } @@ -8965,7 +9129,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } try { nameLayout = new StaticLayout(nameStringFinal, Theme.chat_namePaint, nameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (nameLayout != null && nameLayout.getLineCount() > 0) { + if (nameLayout.getLineCount() > 0) { nameWidth = (int) Math.ceil(nameLayout.getLineWidth(0)); if (!messageObject.isAnyKindOfSticker()) { namesOffset += AndroidUtilities.dp(19); @@ -9021,7 +9185,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); - } else if (currentForwardName != null) { + } else { currentForwardNameString = currentForwardName; } @@ -9124,7 +9288,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (messageObject.replyMessageObject.isRoundVideo()) { replyImageReceiver.setRoundRadius(AndroidUtilities.dp(22)); } else { - replyImageReceiver.setRoundRadius(0); + replyImageReceiver.setRoundRadius(AndroidUtilities.dp(2)); } currentReplyPhoto = photoSize; replyImageReceiver.setImage(ImageLocation.getForObject(photoSize, photoObject), "50_50", ImageLocation.getForObject(thumbPhotoSize, photoObject), "50_50_b", size, null, messageObject.replyMessageObject, cacheType); @@ -9204,7 +9368,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); - } else if (currentForwardName != null) { + } else { currentForwardNameString = currentForwardName; } name = getForwardedMessageText(messageObject); @@ -9276,6 +9440,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate requestLayout(); } + private boolean isNeedAuthorName() { + return isPinnedChat && currentMessageObject.type == 0 || (!pinnedTop || ChatObject.isChannel(currentChat) && !currentChat.megagroup) && drawName && isChat && (!currentMessageObject.isOutOwner() || currentMessageObject.isMegagroup() && currentMessageObject.isFromGroup()); + } + + private String getAuthorName() { + if (currentUser != null) { + return UserObject.getUserName(currentUser); + } else if (currentChat != null) { + return currentChat.title; + } else { + return "DELETED"; + } + } + private String getForwardedMessageText(MessageObject messageObject) { if (hasPsaHint) { String forwardedString = LocaleController.getString("PsaMessage_" + messageObject.messageOwner.fwd_from.psa_type); @@ -9357,7 +9535,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate forceLayout(); return; } - if (!wasLayout && animationRunning) { + if (!wasLayout) { onLayout(false, getLeft(), getTop(), getRight(), getBottom()); } @@ -9385,7 +9563,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate seekBar.setColors(Theme.getColor(Theme.key_chat_inAudioSeekbar), Theme.getColor(Theme.key_chat_inAudioCacheSeekbar), Theme.getColor(Theme.key_chat_inAudioSeekbarFill), Theme.getColor(Theme.key_chat_inAudioSeekbarFill), Theme.getColor(Theme.key_chat_inAudioSeekbarSelected)); } } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { - documentAttachType = DOCUMENT_ATTACH_TYPE_MUSIC; if (currentMessageObject.isOutOwner()) { seekBar.setColors(Theme.getColor(Theme.key_chat_outAudioSeekbar), Theme.getColor(Theme.key_chat_outAudioCacheSeekbar), Theme.getColor(Theme.key_chat_outAudioSeekbarFill), Theme.getColor(Theme.key_chat_outAudioSeekbarFill), Theme.getColor(Theme.key_chat_outAudioSeekbarSelected)); } else { @@ -9414,12 +9591,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Drawable currentBackgroundShadowDrawable; int additionalTop = 0; int additionalBottom = 0; + boolean forceMediaByGroup = currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) == 0 && currentMessagesGroup.isDocuments && !drawPinnedBottom; if (currentMessageObject.isOutOwner()) { - if (transitionParams.changePinnedBottomProgress != 1) { - currentBackgroundDrawable = Theme.chat_msgOutMediaDrawable; - currentBackgroundSelectedDrawable = Theme.chat_msgOutMediaSelectedDrawable; - transitionParams.drawPinnedBottomBackground = true; - } else if (!mediaBackground && !drawPinnedBottom) { + if (transitionParams.changePinnedBottomProgress >= 1 && !mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = Theme.chat_msgOutDrawable; currentBackgroundSelectedDrawable = Theme.chat_msgOutSelectedDrawable; transitionParams.drawPinnedBottomBackground = false; @@ -9436,14 +9610,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } backgroundDrawableLeft = layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)); backgroundDrawableRight = backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)); - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (!currentPosition.edge) { backgroundDrawableRight += AndroidUtilities.dp(10); } } int backgroundLeft = backgroundDrawableLeft; - if (transitionParams.changePinnedBottomProgress != 1) { - backgroundDrawableRight -= AndroidUtilities.dp(6); + if (!forceMediaByGroup && transitionParams.changePinnedBottomProgress != 1) { + if (!mediaBackground) { + backgroundDrawableRight -= AndroidUtilities.dp(6); + } } else if (!mediaBackground && drawPinnedBottom) { backgroundDrawableRight -= AndroidUtilities.dp(6); } @@ -9472,18 +9648,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { offsetBottom = AndroidUtilities.dp(2); } - backgroundDrawableTop = additionalTop + (drawPinnedTop || drawPinnedTop && drawPinnedBottom ? 0 : AndroidUtilities.dp(1)); + backgroundDrawableTop = additionalTop + (drawPinnedTop ? 0 : AndroidUtilities.dp(1)); int backgroundHeight = layoutHeight - offsetBottom + additionalBottom; backgroundDrawableBottom = backgroundDrawableTop + backgroundHeight; - setDrawableBoundsInner(currentBackgroundDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); - setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); + if (forceMediaByGroup) { + setDrawableBoundsInner(currentBackgroundDrawable, backgroundLeft, backgroundDrawableTop - additionalTop, backgroundDrawableRight, backgroundHeight - additionalBottom + 10); + setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight - AndroidUtilities.dp(6), backgroundHeight); + } else { + setDrawableBoundsInner(currentBackgroundDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); + setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); + } setDrawableBoundsInner(currentBackgroundShadowDrawable, backgroundLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } else { - if (transitionParams.changePinnedBottomProgress != 1) { - currentBackgroundDrawable = Theme.chat_msgInMediaDrawable; - currentBackgroundSelectedDrawable = Theme.chat_msgInMediaSelectedDrawable; - transitionParams.drawPinnedBottomBackground = true; - } else if (!mediaBackground && !drawPinnedBottom) { + if (transitionParams.changePinnedBottomProgress >= 1 && !mediaBackground && !drawPinnedBottom && !forceMediaByGroup) { currentBackgroundDrawable = Theme.chat_msgInDrawable; currentBackgroundSelectedDrawable = Theme.chat_msgInSelectedDrawable; transitionParams.drawPinnedBottomBackground = false; @@ -9501,7 +9678,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate backgroundDrawableLeft = AndroidUtilities.dp((isChat && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); backgroundDrawableRight = backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)); - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (!currentPosition.edge) { backgroundDrawableLeft -= AndroidUtilities.dp(10); backgroundDrawableRight += AndroidUtilities.dp(10); @@ -9510,9 +9687,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate backgroundDrawableLeft += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } - if ((!mediaBackground && drawPinnedBottom) || transitionParams.changePinnedBottomProgress != 1) { - backgroundDrawableRight -= AndroidUtilities.dp(6); - backgroundDrawableLeft += AndroidUtilities.dp(6); + if ((!mediaBackground && drawPinnedBottom) || !forceMediaByGroup && transitionParams.changePinnedBottomProgress != 1) { + if (!(!drawPinnedBottom && mediaBackground)) { + backgroundDrawableRight -= AndroidUtilities.dp(6); + } + if (!mediaBackground) { + backgroundDrawableLeft += AndroidUtilities.dp(6); + } + } if (currentPosition != null) { if ((currentPosition.flags & MessageObject.POSITION_FLAG_RIGHT) == 0) { @@ -9538,15 +9720,19 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } else { offsetBottom = AndroidUtilities.dp(2); } - backgroundDrawableTop = additionalTop + (drawPinnedTop || drawPinnedTop && drawPinnedBottom ? 0 : AndroidUtilities.dp(1)); + backgroundDrawableTop = additionalTop + (drawPinnedTop ? 0 : AndroidUtilities.dp(1)); int backgroundHeight = layoutHeight - offsetBottom + additionalBottom; backgroundDrawableBottom = backgroundDrawableTop + backgroundHeight; setDrawableBoundsInner(currentBackgroundDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); - setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); + if (forceMediaByGroup) { + setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft + AndroidUtilities.dp(6), backgroundDrawableTop, backgroundDrawableRight - AndroidUtilities.dp(6), backgroundHeight); + } else { + setDrawableBoundsInner(currentBackgroundSelectedDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); + } setDrawableBoundsInner(currentBackgroundShadowDrawable, backgroundDrawableLeft, backgroundDrawableTop, backgroundDrawableRight, backgroundHeight); } - if (!currentMessageObject.isOutOwner() && transitionParams.changePinnedBottomProgress != 1 && (!mediaBackground && !drawPinnedBottom)) { + if (!currentMessageObject.isOutOwner() && transitionParams.changePinnedBottomProgress != 1 && !mediaBackground && !drawPinnedBottom) { backgroundDrawableLeft -= AndroidUtilities.dp(6); backgroundDrawableRight += AndroidUtilities.dp(6); } @@ -9614,35 +9800,48 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (drawBackground && currentBackgroundDrawable != null && currentPosition == null) { + if (drawBackground && currentBackgroundDrawable != null && (currentPosition == null || isDrawSelectionBackground() && (currentMessageObject.isMusic() || currentMessageObject.isDocument()))) { if (isHighlightedAnimated) { currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.draw(canvas); float alpha = highlightProgress >= 300 ? 1.0f : highlightProgress / 300.0f; + currentSelectedBackgroundAlpha = alpha; if (currentPosition == null) { currentBackgroundSelectedDrawable.setAlpha((int) (alphaInternal * alpha * 255)); currentBackgroundSelectedDrawable.draw(canvas); } - } else if (selectedBackgroundProgress != 0) { + } else if (selectedBackgroundProgress != 0 && !(currentMessagesGroup != null && currentMessagesGroup.isDocuments)) { currentBackgroundDrawable.draw(canvas); + currentSelectedBackgroundAlpha = selectedBackgroundProgress; currentBackgroundSelectedDrawable.setAlpha((int) (selectedBackgroundProgress * alphaInternal * 255)); currentBackgroundSelectedDrawable.draw(canvas); - currentBackgroundShadowDrawable = null; + if (currentBackgroundDrawable.getGradientShader() == null) { + currentBackgroundShadowDrawable = null; + } } else { - if (isDrawSelectionBackground() && (currentPosition == null || getBackground() != null)) { + if (isDrawSelectionBackground() && (currentPosition == null || currentMessageObject.isMusic() || currentMessageObject.isDocument() || getBackground() != null)) { + if (currentPosition != null) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + currentSelectedBackgroundAlpha = 1f; currentBackgroundSelectedDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundSelectedDrawable.draw(canvas); + if (currentPosition != null) { + canvas.restore(); + } } else { + currentSelectedBackgroundAlpha = 0; currentBackgroundDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundDrawable.draw(canvas); } } - if (currentBackgroundShadowDrawable != null && (currentPosition == null || currentPosition.flags != 0)) { + if (currentBackgroundShadowDrawable != null && currentPosition == null) { currentBackgroundShadowDrawable.setAlpha((int) (255 * alphaInternal)); currentBackgroundShadowDrawable.draw(canvas); } - if (transitionParams.changePinnedBottomProgress != 1f) { + if (transitionParams.changePinnedBottomProgress != 1f && currentPosition == null) { if (currentMessageObject.isOutOwner()) { Theme.MessageDrawable drawable = Theme.chat_msgOutDrawable; @@ -9658,7 +9857,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate h = view.getMeasuredHeight(); } } - drawable.setTop((int) getY(), h, pinnedTop, pinnedBottom); + drawable.setTop((int) (getY() + parentViewTopOffset), h, pinnedTop, pinnedBottom); float alpha = !mediaBackground && !pinnedBottom ? transitionParams.changePinnedBottomProgress : (1f - transitionParams.changePinnedBottomProgress); drawable.setAlpha((int) (255 * alpha)); drawable.draw(canvas); @@ -9817,8 +10016,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate setDrawableBounds(Theme.chat_shareDrawable, sideStartX, sideStartY, AndroidUtilities.dp(32), AndroidUtilities.dp(32)); Theme.chat_shareDrawable.draw(canvas); if (drawSideButton == 2) { - setDrawableBounds(Theme.chat_goIconDrawable, sideStartX + AndroidUtilities.dp(12), sideStartY + AndroidUtilities.dp(9)); + if (currentMessageObject.isOutOwner()) { + setDrawableBounds(Theme.chat_goIconDrawable, sideStartX + AndroidUtilities.dp(10), sideStartY + AndroidUtilities.dp(9)); + canvas.save(); + canvas.scale(-1, 1, Theme.chat_goIconDrawable.getBounds().centerX(), Theme.chat_goIconDrawable.getBounds().centerY()); + } else { + setDrawableBounds(Theme.chat_goIconDrawable, sideStartX + AndroidUtilities.dp(12), sideStartY + AndroidUtilities.dp(9)); + } Theme.chat_goIconDrawable.draw(canvas); + if (currentMessageObject.isOutOwner()) { + canvas.restore(); + } } else { setDrawableBounds(Theme.chat_shareIconDrawable, sideStartX + AndroidUtilities.dp(8), sideStartY + AndroidUtilities.dp(9)); Theme.chat_shareIconDrawable.draw(canvas); @@ -9843,21 +10051,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaBackground) { replyStartX = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); } else { - replyStartX = backgroundDrawableLeft + AndroidUtilities.dp(!mediaBackground && drawPinnedBottom ? 12 : 18) + getExtraTextX(); + replyStartX = backgroundDrawableLeft + AndroidUtilities.dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } } replyStartY = AndroidUtilities.dp(12 + (drawForwardedName && forwardedNameLayout[0] != null ? 36 : 0) + (drawNameLayout && nameLayout != null ? 20 : 0)); } } - if (currentPosition == null) { + if (currentPosition == null && !transitionParams.animateBackgroundBoundsInner) { drawNamesLayout(canvas, 1f); } - if (!autoPlayingMedia || !MediaController.getInstance().isPlayingMessageAndReadyToDraw(currentMessageObject)) { + if (!autoPlayingMedia || !MediaController.getInstance().isPlayingMessageAndReadyToDraw(currentMessageObject) && !transitionParams.animateBackgroundBoundsInner) { drawOverlays(canvas); } if ((drawTime || !mediaBackground) && !forceNotDrawTime && !transitionParams.animateBackgroundBoundsInner) { - drawTime(canvas, 1f); + drawTime(canvas, 1f, false); } if ((controlsAlpha != 1.0f || timeAlpha != 1.0f) && currentMessageObject.type != 5) { @@ -9913,11 +10121,14 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)); } else { int r = AndroidUtilities.dp((isChat && isAvatarVisible ? 48 : 0) + (!mediaBackground ? 3 : 9)); - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { if (currentPosition.leftSpanOffset != 0) { r += (int) Math.ceil(currentPosition.leftSpanOffset / 1000.0f * getGroupPhotosWidth()); } } + if ((!mediaBackground && drawPinnedBottom)) { + r += AndroidUtilities.dp(6); + } return r; } } @@ -9927,6 +10138,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!mediaBackground && drawPinnedBottom && currentMessageObject.isOutOwner()) { right -= AndroidUtilities.dp(6); } + if (!mediaBackground && drawPinnedBottom && !currentMessageObject.isOutOwner()) { + right -= AndroidUtilities.dp(6); + } return getBackgroundDrawableLeft() + right; } @@ -9937,7 +10151,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate additionalTop -= AndroidUtilities.dp( 3); } } - return additionalTop + (drawPinnedTop || drawPinnedTop && drawPinnedBottom ? 0 : AndroidUtilities.dp(1)); + return additionalTop + (drawPinnedTop ? 0 : AndroidUtilities.dp(1)); } public int getBackgroundDrawableBottom() { @@ -9970,7 +10184,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate currentBackgroundDrawable = Theme.chat_msgOutMediaDrawable; } } else { - if (!mediaBackground && !pinnedTop) { + if (!mediaBackground && !pinnedBottom) { currentBackgroundDrawable = Theme.chat_msgInDrawable; } else { currentBackgroundDrawable = Theme.chat_msgInMediaDrawable; @@ -9985,22 +10199,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate h = view.getMeasuredHeight(); } } - currentBackgroundDrawable.setTop(0, h, pinnedTop, pinnedBottom); - - Drawable currentBackgroundShadowDrawable = null; - - if (currentBackgroundDrawable != null) { - currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); - } - - if (currentBackgroundShadowDrawable != null) { - currentBackgroundShadowDrawable.setAlpha((int) (getAlpha() * 255)); - currentBackgroundShadowDrawable.setBounds(left, top, right, bottom); - currentBackgroundShadowDrawable.draw(canvas); - currentBackgroundShadowDrawable.setAlpha(255); - } if (currentBackgroundDrawable != null) { + currentBackgroundDrawable.setTop(0, h, pinnedTop, pinnedBottom); + Drawable currentBackgroundShadowDrawable = currentBackgroundDrawable.getShadowDrawable(); + if (currentBackgroundShadowDrawable != null) { + currentBackgroundShadowDrawable.setAlpha((int) (getAlpha() * 255)); + currentBackgroundShadowDrawable.setBounds(left, top, right, bottom); + currentBackgroundShadowDrawable.draw(canvas); + currentBackgroundShadowDrawable.setAlpha(255); + } currentBackgroundDrawable.setAlpha((int) (getAlpha() * 255)); currentBackgroundDrawable.setBounds(left, top, right, bottom); currentBackgroundDrawable.draw(canvas); @@ -10008,7 +10216,6 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - public boolean hasNameLayout() { return drawNameLayout && nameLayout != null || drawForwardedName && forwardedNameLayout[0] != null && forwardedNameLayout[1] != null && (currentPosition == null || currentPosition.minY == 0 && currentPosition.minX == 0) || @@ -10048,11 +10255,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_namePaint.setColor(Theme.getColor(Theme.key_chat_stickerNameText)); - int backWidth; if (currentMessageObject.isOutOwner()) { nameX = AndroidUtilities.dp(28); } else { - nameX = backgroundDrawableLeft + backgroundDrawableRight + AndroidUtilities.dp(22); + nameX = backgroundDrawableLeft + transitionParams.deltaLeft + backgroundDrawableRight + AndroidUtilities.dp(22); } nameY = layoutHeight - AndroidUtilities.dp(38); float alphaProgress = currentMessageObject.isOut() && (checkBoxVisible || checkBoxAnimationInProgress) ? (1.0f - checkBoxAnimationProgress) : 1.0f; @@ -10075,12 +10281,16 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_systemDrawable.setAlpha(255); } else { if (mediaBackground || currentMessageObject.isOutOwner()) { - nameX = backgroundDrawableLeft + AndroidUtilities.dp(11) - nameOffsetX + getExtraTextX(); + nameX = backgroundDrawableLeft + transitionParams.deltaLeft + AndroidUtilities.dp(11) - nameOffsetX + getExtraTextX(); } else { - nameX = backgroundDrawableLeft + AndroidUtilities.dp(!mediaBackground && drawPinnedBottom ? 11 : 17) - nameOffsetX + getExtraTextX(); + nameX = backgroundDrawableLeft + transitionParams.deltaLeft + AndroidUtilities.dp(!mediaBackground && drawPinnedBottom ? 11 : 17) - nameOffsetX + getExtraTextX(); } if (currentUser != null) { - Theme.chat_namePaint.setColor(AvatarDrawable.getNameColorForId(currentUser.id)); + if (currentBackgroundDrawable.hasGradient()) { + Theme.chat_namePaint.setColor(Theme.getColor(Theme.key_chat_messageTextOut)); + } else { + Theme.chat_namePaint.setColor(AvatarDrawable.getNameColorForId(currentUser.id)); + } } else if (currentChat != null) { if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { Theme.chat_namePaint.setColor(Theme.changeColorAccent(AvatarDrawable.getNameColorForId(5))); @@ -10094,6 +10304,12 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } nameY = AndroidUtilities.dp(drawPinnedTop ? 9 : 10); } + if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { + nameX += currentMessagesGroup.transitionParams.offsetLeft; + nameY += currentMessagesGroup.transitionParams.offsetTop - getTranslationY(); + } + nameX += animationOffsetX; + nameY += transitionParams.deltaTop; float nx; if (transitionParams.animateSign) { nx = transitionParams.animateNameX + (nameX - transitionParams.animateNameX) * transitionParams.animateChangeProgress; @@ -10113,7 +10329,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_adminPaint.setColor(color); canvas.save(); float ax; - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessagesGroup.isDocuments) { int dWidth = getGroupPhotosWidth(); int firstLineWidth = 0; for (int a = 0; a < currentMessagesGroup.posArray.size(); a++) { @@ -10161,7 +10377,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate int backWidth = forwardedNameWidth + AndroidUtilities.dp(14); Theme.chat_systemDrawable.setColorFilter(Theme.colorFilter); - Theme.chat_systemDrawable.setBounds(forwardNameX - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), forwardNameX - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); + Theme.chat_systemDrawable.setBounds((int) forwardNameX - AndroidUtilities.dp(7), forwardNameY - AndroidUtilities.dp(6), (int) forwardNameX - AndroidUtilities.dp(7) + backWidth, forwardNameY + AndroidUtilities.dp(38)); Theme.chat_systemDrawable.draw(canvas); } else { forwardNameY = AndroidUtilities.dp(10 + (drawNameLayout ? 19 : 0)); @@ -10181,7 +10397,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaBackground) { forwardNameX = backgroundDrawableLeft + AndroidUtilities.dp(11) + getExtraTextX(); } else { - forwardNameX = backgroundDrawableLeft + AndroidUtilities.dp(!mediaBackground && drawPinnedBottom ? 11 : 17) + getExtraTextX(); + forwardNameX = backgroundDrawableLeft + AndroidUtilities.dp(drawPinnedBottom ? 11 : 17) + getExtraTextX(); } } } @@ -10229,13 +10445,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (replyNameLayout != null) { + float replyStartX = this.replyStartX; + if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { + replyStartX += currentMessagesGroup.transitionParams.offsetLeft; + } + if (transitionParams.animateBackgroundBoundsInner) { + replyStartX += transitionParams.deltaLeft; + } if (currentMessageObject.shouldDrawWithoutBackground()) { Theme.chat_replyLinePaint.setColor(Theme.getColor(Theme.key_chat_stickerReplyLine)); Theme.chat_replyNamePaint.setColor(Theme.getColor(Theme.key_chat_stickerReplyNameText)); Theme.chat_replyTextPaint.setColor(Theme.getColor(Theme.key_chat_stickerReplyMessageText)); int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14); Theme.chat_systemDrawable.setColorFilter(Theme.colorFilter); - Theme.chat_systemDrawable.setBounds(replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); + Theme.chat_systemDrawable.setBounds((int) replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), (int) replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); Theme.chat_systemDrawable.draw(canvas); } else { if (currentMessageObject.isOutOwner()) { @@ -10320,11 +10543,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate checkBox.onAttachedToWindow(); } } - if (visible && photoCheckBox == null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { - photoCheckBox = new CheckBoxBase(this, 21); - photoCheckBox.setUseDefaultCheck(true); + if (visible && mediaCheckBox == null && currentMessagesGroup != null && currentMessagesGroup.messages.size() > 1) { + mediaCheckBox = new CheckBoxBase(this, 21); + mediaCheckBox.setUseDefaultCheck(true); if (attachedToWindow) { - photoCheckBox.onAttachedToWindow(); + mediaCheckBox.onAttachedToWindow(); } } if (checkBoxVisible == visible) { @@ -10348,8 +10571,8 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (checkBox != null) { checkBox.setChecked(allChecked, animated); } - if (photoCheckBox != null) { - photoCheckBox.setChecked(checked, animated); + if (mediaCheckBox != null) { + mediaCheckBox.setChecked(checked, animated); } backgroundDrawable.setSelected(allChecked, animated); } @@ -10384,10 +10607,10 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (mediaBackground) { x = backgroundDrawableLeft + AndroidUtilities.dp(12) + getExtraTextX(); } else { - x = backgroundDrawableLeft + AndroidUtilities.dp(!mediaBackground && drawPinnedBottom ? 12 : 18) + getExtraTextX(); + x = backgroundDrawableLeft + AndroidUtilities.dp(drawPinnedBottom ? 12 : 18) + getExtraTextX(); } int endX = x - getExtraTextX(); - if (currentMessagesGroup != null) { + if (currentMessagesGroup != null && !currentMessageObject.isMusic() && !currentMessageObject.isDocument()) { int dWidth = getGroupPhotosWidth(); if ((currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) == 0) { endX += Math.ceil(currentPosition.pw / 1000.0f * dWidth); @@ -10434,7 +10657,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentPosition == null || (currentPosition.flags & MessageObject.POSITION_FLAG_LEFT) != 0 && currentPosition.minX == 0 && currentPosition.maxX == 0) { Theme.chat_instantViewPaint.setColor(Theme.getColor(Theme.key_chat_inPreviewInstantText)); boolean drawnAvatars = false; - int avatarsOffset = 0; + int avatarsOffset = 2; if (commentAvatarImages != null) { int toAdd = AndroidUtilities.dp(17); int ax = x + getExtraTextX(); @@ -10449,7 +10672,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } commentAvatarImages[a].draw(canvas); drawnAvatars = true; - avatarsOffset += a == 0 ? 2 : 17; + if (a != 0) { + avatarsOffset += 17; + } } } if (!mediaBackground || captionLayout != null) { @@ -10463,17 +10688,23 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } if (commentLayout != null && drawSideButton != 3) { Theme.chat_replyNamePaint.setColor(Theme.getColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outPreviewInstantText : Theme.key_chat_inPreviewInstantText)); + commentX = x + AndroidUtilities.dp(33 + avatarsOffset); + if (drawCommentNumber) { + commentX += commentNumberWidth + AndroidUtilities.dp(4); + } + int prevAlpha = Theme.chat_replyNamePaint.getAlpha(); if (transitionParams.animateComments) { if (transitionParams.animateCommentsLayout != null) { canvas.save(); - Theme.chat_replyNamePaint.setAlpha((int) (255 * (1.0 - transitionParams.animateChangeProgress))); - canvas.translate(x + AndroidUtilities.dp(33 + avatarsOffset), y - AndroidUtilities.dp(0.1f) + (pinnedBottom ? AndroidUtilities.dp(2) : 0)); + Theme.chat_replyNamePaint.setAlpha((int) (prevAlpha * (1.0 - transitionParams.animateChangeProgress))); + float cx = transitionParams.animateCommentX + (commentX - transitionParams.animateCommentX) * transitionParams.animateChangeProgress; + canvas.translate(cx, y - AndroidUtilities.dp(0.1f) + (pinnedBottom ? AndroidUtilities.dp(2) : 0)); transitionParams.animateCommentsLayout.draw(canvas); canvas.restore(); } - Theme.chat_replyNamePaint.setAlpha((int) (255 * transitionParams.animateChangeProgress)); } - int prevAlpha = Theme.chat_replyNamePaint.getAlpha(); + canvas.save(); + canvas.translate(x + AndroidUtilities.dp(33 + avatarsOffset), y - AndroidUtilities.dp(0.1f) + (pinnedBottom ? AndroidUtilities.dp(2) : 0)); if (!currentMessageObject.isSent()) { Theme.chat_replyNamePaint.setAlpha(127); Theme.chat_commentArrowDrawable.setAlpha(127); @@ -10482,12 +10713,42 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_commentArrowDrawable.setAlpha(255); Theme.chat_commentDrawable.setAlpha(255); } - canvas.save(); - canvas.translate(x + AndroidUtilities.dp(33 + avatarsOffset), y - AndroidUtilities.dp(0.1f) + (pinnedBottom ? AndroidUtilities.dp(2) : 0)); + if (drawCommentNumber || transitionParams.animateComments && transitionParams.animateDrawCommentNumber) { + if (drawCommentNumber && transitionParams.animateComments) { + if (transitionParams.animateDrawCommentNumber) { + Theme.chat_replyNamePaint.setAlpha(prevAlpha); + } else { + Theme.chat_replyNamePaint.setAlpha((int) (prevAlpha * transitionParams.animateChangeProgress)); + } + } + commentNumberLayout.draw(canvas); + if (drawCommentNumber) { + canvas.translate(commentNumberWidth + AndroidUtilities.dp(4), 0); + } + } + if (transitionParams.animateComments && transitionParams.animateCommentsLayout != null) { + Theme.chat_replyNamePaint.setAlpha((int) (prevAlpha * transitionParams.animateChangeProgress)); + } else { + Theme.chat_replyNamePaint.setAlpha(prevAlpha); + } commentLayout.draw(canvas); canvas.restore(); commentUnreadX = x + commentWidth + AndroidUtilities.dp(33 + avatarsOffset) + AndroidUtilities.dp(9); - if (commentDrawUnread = currentMessageObject.hasReplies() && currentMessageObject.messageOwner.replies.read_max_id != 0 && currentMessageObject.messageOwner.replies.read_max_id < currentMessageObject.messageOwner.replies.max_id) { + if (drawCommentNumber) { + commentUnreadX += commentNumberWidth + AndroidUtilities.dp(4); + } + TLRPC.TL_messageReplies replies = null; + if (currentMessagesGroup != null && !currentMessagesGroup.messages.isEmpty()) { + MessageObject messageObject = currentMessagesGroup.messages.get(0); + if (messageObject.hasReplies()) { + replies = messageObject.messageOwner.replies; + } + } else { + if (currentMessageObject.hasReplies()) { + replies = currentMessageObject.messageOwner.replies; + } + } + if (commentDrawUnread = (replies != null && replies.read_max_id != 0 && replies.read_max_id < replies.max_id)) { int color = Theme.getColor(Theme.key_chat_inInstant); Theme.chat_docBackPaint.setColor(color); int unreadX; @@ -10634,10 +10895,59 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } private boolean shouldDrawTimeOnMedia() { + if (overideShouldDrawTimeOnMedia != 0) { + return overideShouldDrawTimeOnMedia == 1; + } return mediaBackground && captionLayout == null || isMedia && drawCommentButton && !isRepliesChat; } - public void drawTime(Canvas canvas, float alpha) { + public void drawTime(Canvas canvas, float alpha, boolean fromParent) { + for (int i = 0; i < 2; i++) { + float curentAplha = alpha; + if (i == 0 && isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 1f && !shouldDrawTimeOnMedia()) { + continue; + } else if (i == 1 && ((!isDrawSelectionBackground() && currentSelectedBackgroundAlpha == 0) || shouldDrawTimeOnMedia())) { + break; + } + boolean drawSelectionBackground = i == 1; + if (i == 1) { + curentAplha *= currentSelectedBackgroundAlpha; + } else if (!shouldDrawTimeOnMedia()){ + curentAplha *= (1f - currentSelectedBackgroundAlpha); + } + if (transitionParams.animateShouldDrawTimeOnMedia && transitionParams.animateChangeProgress != 1f) { + if (shouldDrawTimeOnMedia()) { + overideShouldDrawTimeOnMedia = 1; + drawTimeInternal(canvas, curentAplha * transitionParams.animateChangeProgress, fromParent, this.timeX, timeLayout, timeWidth, drawSelectionBackground); + overideShouldDrawTimeOnMedia = 2; + drawTimeInternal(canvas, curentAplha * (1f - transitionParams.animateChangeProgress), fromParent, transitionParams.animateFromTimeX, transitionParams.animateTimeLayout, transitionParams.animateTimeWidth, drawSelectionBackground); + } else { + overideShouldDrawTimeOnMedia = 2; + drawTimeInternal(canvas, curentAplha * transitionParams.animateChangeProgress, fromParent, this.timeX, timeLayout, timeWidth, drawSelectionBackground); + overideShouldDrawTimeOnMedia = 1; + drawTimeInternal(canvas, curentAplha * (1f - transitionParams.animateChangeProgress), fromParent, transitionParams.animateFromTimeX, transitionParams.animateTimeLayout, transitionParams.animateTimeWidth, drawSelectionBackground); + } + overideShouldDrawTimeOnMedia = 0; + } else { + float timeX; + float timeWidth; + if (transitionParams.shouldAnimateTimeX) { + timeX = this.timeX * transitionParams.animateChangeProgress + transitionParams.animateFromTimeX * (1f - transitionParams.animateChangeProgress); + timeWidth = this.timeWidth * transitionParams.animateChangeProgress + transitionParams.animateTimeWidth * (1f - transitionParams.animateChangeProgress); + } else { + timeX = this.timeX + transitionParams.deltaRight; + timeWidth = this.timeWidth; + } + drawTimeInternal(canvas, curentAplha, fromParent, timeX, timeLayout, timeWidth, drawSelectionBackground); + } + } + + if (transitionParams.animateBackgroundBoundsInner) { + drawOverlays(canvas); + } + } + + private void drawTimeInternal(Canvas canvas, float alpha, boolean fromParent, float timeX, StaticLayout timeLayout, float timeWidth, boolean drawSelectionBackground) { if ((!drawTime || groupPhotoInvisible) && shouldDrawTimeOnMedia() || timeLayout == null || (currentMessageObject.deleted && currentPosition != null) || currentMessageObject.type == 16) { return; } @@ -10652,9 +10962,9 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } else { if (currentMessageObject.isOutOwner()) { - Theme.chat_timePaint.setColor(Theme.getColor(isDrawSelectionBackground() ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText)); + Theme.chat_timePaint.setColor(Theme.getColor(drawSelectionBackground ? Theme.key_chat_outTimeSelectedText : Theme.key_chat_outTimeText)); } else { - Theme.chat_timePaint.setColor(Theme.getColor(isDrawSelectionBackground() ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText)); + Theme.chat_timePaint.setColor(Theme.getColor(drawSelectionBackground ? Theme.key_chat_inTimeSelectedText : Theme.key_chat_inTimeText)); } } } @@ -10664,18 +10974,24 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (alpha != 1f) { Theme.chat_timePaint.setAlpha((int) (Theme.chat_timePaint.getAlpha() * alpha)); } - if (drawPinnedBottom) { + canvas.save(); + if (drawPinnedBottom && !shouldDrawTimeOnMedia()) { canvas.translate(0, AndroidUtilities.dp(2)); } - float timeX = this.timeX + transitionParams.deltaRight; boolean bigRadius = false; float layoutHeight = this.layoutHeight + transitionParams.deltaBottom; + float timeTitleTimeX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + transitionParams.deltaRight; if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { layoutHeight -= getTranslationY(); timeX += currentMessagesGroup.transitionParams.offsetRight; + timeTitleTimeX += currentMessagesGroup.transitionParams.offsetRight; + } + if (drawPinnedBottom && shouldDrawTimeOnMedia()) { + layoutHeight += AndroidUtilities.dp(1); } if (transitionParams.animateBackgroundBoundsInner) { timeX += animationOffsetX; + timeTitleTimeX += animationOffsetX; } int timeYOffset; if (shouldDrawTimeOnMedia()) { @@ -10706,320 +11022,642 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate canvas.drawRoundRect(rect, r, r, paint); paint.setAlpha(oldAlpha); - int additionalX = (int) (-timeLayout.getLineLeft(0)); - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || repliesLayout != null) { - additionalX += (int) (timeWidth - timeLayout.getLineWidth(0)); + float additionalX = -timeLayout.getLineLeft(0); + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || repliesLayout != null || isPinned) { + additionalX += this.timeWidth - timeLayout.getLineWidth(0); - if (currentMessageObject.isSending() || currentMessageObject.isEditing()) { - if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(Theme.chat_msgMediaClockDrawable, timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)), timeY - AndroidUtilities.dp(9.0f) - Theme.chat_msgMediaClockDrawable.getIntrinsicHeight()); - Theme.chat_msgMediaClockDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgMediaClockDrawable.draw(canvas); - Theme.chat_msgMediaClockDrawable.setAlpha(255); - } - } else if (currentMessageObject.isSendError()) { - if (!currentMessageObject.isOutOwner()) { - float x = timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)); - float y = timeY - AndroidUtilities.dp(21.5f); - rect.set(x, y, x + AndroidUtilities.dp(14), y + AndroidUtilities.dp(14)); - oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); - Theme.chat_msgErrorPaint.setAlpha((int) (oldAlpha * alpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_msgErrorPaint); - Theme.chat_msgErrorPaint.setAlpha(oldAlpha); - setDrawableBounds(Theme.chat_msgErrorDrawable, x + AndroidUtilities.dp(6), y + AndroidUtilities.dp(2)); - Theme.chat_msgErrorDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgErrorDrawable.draw(canvas); - Theme.chat_msgErrorDrawable.setAlpha(255); - } + int currentStatus = transitionParams.createStatusDrawableParams(); + if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { + createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); + } + if (statusDrawableAnimationInProgress) { + currentStatus = animateToStatusDrawableParams; + } + + boolean drawClock = (currentStatus & 4) != 0; + boolean drawError = (currentStatus & 8) != 0; + + if (statusDrawableAnimationInProgress) { + boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; + boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; + drawViewsAndRepliesLayout(canvas, outDrawClock, outDrawError, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); + drawViewsAndRepliesLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); } else { - int offsetX = 0; - if (repliesLayout != null) { - Drawable repliesDrawable; - if (currentMessageObject.shouldDrawWithoutBackground()) { - repliesDrawable = Theme.chat_msgStickerRepliesDrawable; - } else { - repliesDrawable = Theme.chat_msgMediaRepliesDrawable; - } - oldAlpha = ((BitmapDrawable) repliesDrawable).getPaint().getAlpha(); - repliesDrawable.setAlpha((int) (timeAlpha * oldAlpha * alpha)); - setDrawableBounds(repliesDrawable, timeX, timeY - AndroidUtilities.dp(7.5f) - timeLayout.getHeight()); - repliesDrawable.draw(canvas); - repliesDrawable.setAlpha(oldAlpha); + drawViewsAndRepliesLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); + } - if (transitionParams.animateReplies) { - if (transitionParams.animateRepliesLayout != null) { - canvas.save(); - Theme.chat_timePaint.setAlpha((int) (255 * (1.0 - transitionParams.animateChangeProgress))); - canvas.translate(timeX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), timeY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight()); - transitionParams.animateRepliesLayout.draw(canvas); - canvas.restore(); - } - Theme.chat_timePaint.setAlpha((int) (255 * transitionParams.animateChangeProgress)); - } - canvas.save(); - canvas.translate(timeX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), timeY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight()); - repliesLayout.draw(canvas); - canvas.restore(); - offsetX = repliesDrawable.getIntrinsicWidth() + repliesTextWidth + AndroidUtilities.dp(10); - } - if (viewsLayout != null) { - Drawable viewsDrawable; - if (currentMessageObject.shouldDrawWithoutBackground()) { - viewsDrawable = Theme.chat_msgStickerViewsDrawable; - } else { - viewsDrawable = Theme.chat_msgMediaViewsDrawable; - } - oldAlpha = ((BitmapDrawable) viewsDrawable).getPaint().getAlpha(); - viewsDrawable.setAlpha((int) (timeAlpha * oldAlpha * alpha)); - setDrawableBounds(viewsDrawable, timeX + offsetX, timeY - AndroidUtilities.dp(5.5f) - timeLayout.getHeight()); - viewsDrawable.draw(canvas); - viewsDrawable.setAlpha(oldAlpha); + transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); - canvas.save(); - canvas.translate(timeX + viewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) + offsetX, timeY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight()); - viewsLayout.draw(canvas); - canvas.restore(); - } + if (drawClock && fromParent && getParent() != null) { + ((View)getParent()).invalidate(); } } canvas.save(); - canvas.translate(timeX + additionalX, timeY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight()); + canvas.translate(timeTitleTimeX + additionalX, timeY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight()); timeLayout.draw(canvas); canvas.restore(); Theme.chat_timePaint.setAlpha(255); } else { timeYOffset = -(drawCommentButton ? AndroidUtilities.dp(43) : 0); - int additionalX = (int) (-timeLayout.getLineLeft(0)); - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || repliesLayout != null) { - additionalX += (int) (timeWidth - timeLayout.getLineWidth(0)); + float additionalX = -timeLayout.getLineLeft(0); + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup || (currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0 || (repliesLayout != null || transitionParams.animateReplies) || (isPinned || transitionParams.animatePinned)) { + additionalX += this.timeWidth - timeLayout.getLineWidth(0); - if (currentMessageObject.isSending() || currentMessageObject.isEditing()) { - if (!currentMessageObject.isOutOwner()) { - Drawable clockDrawable = isDrawSelectionBackground() ? Theme.chat_msgInSelectedClockDrawable : Theme.chat_msgInClockDrawable; - setDrawableBounds(clockDrawable, timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9.5f : 8.5f) - clockDrawable.getIntrinsicHeight() + timeYOffset); - clockDrawable.setAlpha((int) (255 * alpha)); - clockDrawable.draw(canvas); - clockDrawable.setAlpha(255); - } - } else if (currentMessageObject.isSendError()) { - if (!currentMessageObject.isOutOwner()) { - float x = timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)); - float y = layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 21.5f : 20.5f) + timeYOffset; - rect.set(x, y, x + AndroidUtilities.dp(14), y + AndroidUtilities.dp(14)); - int oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); - Theme.chat_msgErrorPaint.setAlpha((int) (255 * alpha)); - canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_msgErrorPaint); - Theme.chat_msgErrorPaint.setAlpha(oldAlpha); - setDrawableBounds(Theme.chat_msgErrorDrawable, x + AndroidUtilities.dp(6), y + AndroidUtilities.dp(2)); - Theme.chat_msgErrorDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgErrorDrawable.draw(canvas); - Theme.chat_msgErrorDrawable.setAlpha(255); - } + int currentStatus = transitionParams.createStatusDrawableParams(); + if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { + createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); + } + if (statusDrawableAnimationInProgress) { + currentStatus = animateToStatusDrawableParams; + } + + boolean drawClock = (currentStatus & 4) != 0; + boolean drawError = (currentStatus & 8) != 0; + + if (statusDrawableAnimationInProgress) { + boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; + boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; + drawViewsAndRepliesLayout(canvas, outDrawClock, outDrawError, layoutHeight, alpha, timeYOffset, timeX, 1f - statusDrawableProgress, drawSelectionBackground); + drawViewsAndRepliesLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, statusDrawableProgress, drawSelectionBackground); } else { - int offsetX = 0; - if (repliesLayout != null) { - Drawable repliesDrawable; - if (!currentMessageObject.isOutOwner()) { - repliesDrawable = isDrawSelectionBackground() ? Theme.chat_msgInRepliesSelectedDrawable : Theme.chat_msgInRepliesDrawable; - } else { - repliesDrawable = isDrawSelectionBackground() ? Theme.chat_msgOutRepliesSelectedDrawable : Theme.chat_msgOutRepliesDrawable; - } - setDrawableBounds(repliesDrawable, timeX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); - repliesDrawable.setAlpha((int) (255 * alpha)); - repliesDrawable.draw(canvas); - repliesDrawable.setAlpha(255); + drawViewsAndRepliesLayout(canvas, drawClock, drawError, layoutHeight, alpha, timeYOffset, timeX, 1f, drawSelectionBackground); + } - if (transitionParams.animateReplies) { - if (transitionParams.animateRepliesLayout != null) { - canvas.save(); - Theme.chat_timePaint.setAlpha((int) (255 * (1.0 - transitionParams.animateChangeProgress))); - canvas.translate(timeX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); - transitionParams.animateRepliesLayout.draw(canvas); - canvas.restore(); - } - Theme.chat_timePaint.setAlpha((int) (255 * transitionParams.animateChangeProgress)); - } - canvas.save(); - canvas.translate(timeX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); - repliesLayout.draw(canvas); - canvas.restore(); - offsetX = repliesDrawable.getIntrinsicWidth() + repliesTextWidth + AndroidUtilities.dp(10); - } - if (viewsLayout != null) { - Drawable viewsDrawable; - if (!currentMessageObject.isOutOwner()) { - viewsDrawable = isDrawSelectionBackground() ? Theme.chat_msgInViewsSelectedDrawable : Theme.chat_msgInViewsDrawable; - } else { - viewsDrawable = isDrawSelectionBackground() ? Theme.chat_msgOutViewsSelectedDrawable : Theme.chat_msgOutViewsDrawable; - } - setDrawableBounds(viewsDrawable, timeX + offsetX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 5.5f : 4.5f) - timeLayout.getHeight() + timeYOffset); - viewsDrawable.setAlpha((int) (255 * alpha)); - viewsDrawable.draw(canvas); - viewsDrawable.setAlpha(255); + transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); - canvas.save(); - canvas.translate(timeX + viewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) + offsetX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); - viewsLayout.draw(canvas); - canvas.restore(); - } + if (drawClock && fromParent && getParent() != null) { + ((View)getParent()).invalidate(); } } - canvas.save(); - canvas.translate(timeX + additionalX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); if (transitionParams.animateEditedEnter && transitionParams.animateChangeProgress != 1f) { - int oldAlpha = Theme.chat_timePaint.getAlpha(); - Theme.chat_timePaint.setAlpha((int) (oldAlpha * transitionParams.animateChangeProgress)); - transitionParams.animateEditedLayout.draw(canvas); - Theme.chat_timePaint.setAlpha(oldAlpha); - transitionParams.animateTimeLayout.draw(canvas); + if (transitionParams.animateEditedLayout != null) { + canvas.translate(timeTitleTimeX + additionalX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); + int oldAlpha = Theme.chat_timePaint.getAlpha(); + Theme.chat_timePaint.setAlpha((int) (oldAlpha * transitionParams.animateChangeProgress)); + transitionParams.animateEditedLayout.draw(canvas); + Theme.chat_timePaint.setAlpha(oldAlpha); + transitionParams.animateTimeLayout.draw(canvas); + } else { + int oldAlpha = Theme.chat_timePaint.getAlpha(); + canvas.save(); + canvas.translate(transitionParams.animateFromTimeX + additionalX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); + Theme.chat_timePaint.setAlpha((int) (oldAlpha * (1f - transitionParams.animateChangeProgress))); + transitionParams.animateTimeLayout.draw(canvas); + canvas.restore(); + + canvas.translate(timeTitleTimeX + additionalX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); + Theme.chat_timePaint.setAlpha((int) (oldAlpha * (transitionParams.animateChangeProgress))); + timeLayout.draw(canvas); + Theme.chat_timePaint.setAlpha(oldAlpha); + } } else { + canvas.translate(timeTitleTimeX + additionalX, layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset); timeLayout.draw(canvas); } canvas.restore(); } if (currentMessageObject.isOutOwner()) { - boolean drawCheck1 = false; - boolean drawCheck2 = false; - boolean drawClock = false; - boolean drawError = false; - boolean isBroadcast = (int) (currentMessageObject.getDialogId() >> 32) == 1; - - if (currentMessageObject.isSending() || currentMessageObject.isEditing()) { - drawCheck1 = false; - drawCheck2 = false; - drawClock = true; - drawError = false; - } else if (currentMessageObject.isSendError()) { - drawCheck1 = false; - drawCheck2 = false; - drawClock = false; - drawError = true; - } else if (currentMessageObject.isSent()) { - if (!currentMessageObject.scheduled && !currentMessageObject.isUnread()) { - drawCheck1 = true; - } else { - drawCheck1 = false; - } - drawCheck2 = true; - drawClock = false; - drawError = false; + int currentStatus = transitionParams.createStatusDrawableParams(); + if (transitionParams.lastStatusDrawableParams >= 0 && transitionParams.lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { + createStatusDrawableAnimator(transitionParams.lastStatusDrawableParams, currentStatus, fromParent); } - - if (drawClock) { - if (shouldDrawTimeOnMedia()) { - if (currentMessageObject.shouldDrawWithoutBackground()) { - Theme.chat_msgStickerClockDrawable.setAlpha((int) (255 * timeAlpha * alpha)); - setDrawableBounds(Theme.chat_msgStickerClockDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 24 : 22) - Theme.chat_msgStickerClockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgStickerClockDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgStickerClockDrawable.draw(canvas); - Theme.chat_msgStickerClockDrawable.setAlpha(255); - } else { - setDrawableBounds(Theme.chat_msgMediaClockDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 24 : 22) - Theme.chat_msgMediaClockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgMediaClockDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgMediaClockDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgMediaClockDrawable.draw(canvas); - Theme.chat_msgMediaClockDrawable.setAlpha(255); - } - } else { - setDrawableBounds(Theme.chat_msgOutClockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.chat_msgOutClockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - Theme.chat_msgOutClockDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgOutClockDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgOutClockDrawable.draw(canvas); - Theme.chat_msgOutClockDrawable.setAlpha(255); - } + if (statusDrawableAnimationInProgress) { + currentStatus = animateToStatusDrawableParams; } - - if (isBroadcast) { - if (drawCheck1 || drawCheck2) { - if (shouldDrawTimeOnMedia()) { - setDrawableBounds(Theme.chat_msgBroadcastMediaDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 26 : 24) - Theme.chat_msgBroadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(14.0f) - Theme.chat_msgBroadcastMediaDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgBroadcastMediaDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgBroadcastMediaDrawable.draw(canvas); - Theme.chat_msgBroadcastMediaDrawable.setAlpha(255); - } else { - setDrawableBounds(Theme.chat_msgBroadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.chat_msgBroadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.chat_msgBroadcastDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgBroadcastDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgBroadcastDrawable.draw(canvas); - Theme.chat_msgBroadcastDrawable.setAlpha(255); - } + boolean drawCheck1 = (currentStatus & 1) != 0; + boolean drawCheck2 = (currentStatus & 2) != 0; + boolean drawClock = (currentStatus & 4) != 0; + boolean drawError = (currentStatus & 8) != 0; + boolean isBroadcast = (currentStatus & 16) != 0; + if (statusDrawableAnimationInProgress) { + boolean outDrawCheck1 = (animateFromStatusDrawableParams & 1) != 0; + boolean outDrawCheck2 = (animateFromStatusDrawableParams & 2) != 0; + boolean outDrawClock = (animateFromStatusDrawableParams & 4) != 0; + boolean outDrawError = (animateFromStatusDrawableParams & 8) != 0; + boolean outIsBroadcast = (animateFromStatusDrawableParams & 16) != 0; + if (!outDrawClock && !isBroadcast && !outIsBroadcast && outDrawCheck2 && drawCheck2 && !outDrawCheck1 && drawCheck1) { + drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, isBroadcast, alpha, bigRadius, timeYOffset, layoutHeight, statusDrawableProgress, true, drawSelectionBackground); + } else { + drawStatusDrawable(canvas, outDrawCheck1, outDrawCheck2, outDrawClock, outDrawError, outIsBroadcast, alpha, bigRadius, timeYOffset, layoutHeight,1f - statusDrawableProgress, false, drawSelectionBackground); + drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, isBroadcast, alpha, bigRadius, timeYOffset, layoutHeight, statusDrawableProgress, false, drawSelectionBackground); } } else { - if (drawCheck2) { - if (shouldDrawTimeOnMedia()) { - if (currentMessageObject.shouldDrawWithoutBackground()) { - if (drawCheck1) { - setDrawableBounds(Theme.chat_msgStickerCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 28.3f : 26.3f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicHeight() + timeYOffset); - } else { - setDrawableBounds(Theme.chat_msgStickerCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicHeight() + timeYOffset); - } - Theme.chat_msgStickerCheckDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgStickerCheckDrawable.draw(canvas); - Theme.chat_msgStickerCheckDrawable.setAlpha(255); - } else { - if (drawCheck1) { - setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 28.3f : 26.3f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); - } else { - setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); - } - Theme.chat_msgMediaCheckDrawable.setAlpha((int) (255 * timeAlpha * alpha)); - Theme.chat_msgMediaCheckDrawable.draw(canvas); - Theme.chat_msgMediaCheckDrawable.setAlpha(255); - } - } else { - Drawable drawable; - if (drawCheck1) { - drawable = isDrawSelectionBackground() ? Theme.chat_msgOutCheckReadSelectedDrawable : Theme.chat_msgOutCheckReadDrawable; - setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(22.5f) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); - } else { - drawable = isDrawSelectionBackground() ? Theme.chat_msgOutCheckSelectedDrawable : Theme.chat_msgOutCheckDrawable; - setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(18.5f) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); - } - drawable.setAlpha((int) (255 * alpha)); - drawable.draw(canvas); - drawable.setAlpha(255); - } - } - if (drawCheck1) { - if (shouldDrawTimeOnMedia()) { - if (currentMessageObject.shouldDrawWithoutBackground()) { - setDrawableBounds(Theme.chat_msgStickerHalfCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgStickerHalfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgStickerHalfCheckDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgStickerHalfCheckDrawable.setAlpha((int) (255 * alpha)); - Theme.chat_msgStickerHalfCheckDrawable.draw(canvas); - Theme.chat_msgStickerHalfCheckDrawable.setAlpha(255); - } else { - setDrawableBounds(Theme.chat_msgMediaHalfCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgMediaHalfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.5f) - Theme.chat_msgMediaHalfCheckDrawable.getIntrinsicHeight() + timeYOffset); - Theme.chat_msgMediaHalfCheckDrawable.setAlpha((int) (255 * timeAlpha * alpha)); - Theme.chat_msgMediaHalfCheckDrawable.draw(canvas); - Theme.chat_msgMediaHalfCheckDrawable.setAlpha(255); - } - } else { - Drawable drawable = isDrawSelectionBackground() ? Theme.chat_msgOutHalfCheckSelectedDrawable : Theme.chat_msgOutHalfCheckDrawable; - setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(18) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); - drawable.setAlpha((int) (255 * alpha)); - drawable.draw(canvas); - drawable.setAlpha(255); - } + drawStatusDrawable(canvas, drawCheck1, drawCheck2, drawClock, drawError, isBroadcast, alpha, bigRadius, timeYOffset, layoutHeight, 1, false, drawSelectionBackground); + } + transitionParams.lastStatusDrawableParams = transitionParams.createStatusDrawableParams(); + if (fromParent && drawClock && getParent() != null) { + ((View) getParent()).invalidate(); + } + } + canvas.restore(); + } + + private void createStatusDrawableAnimator(int lastStatusDrawableParams, int currentStatus, boolean fromParent) { + boolean drawCheck1 = (currentStatus & 1) != 0; + boolean drawCheck2 = (currentStatus & 2) != 0; + boolean isBroadcast = (currentStatus & 16) != 0; + + boolean outDrawCheck1 = (lastStatusDrawableParams & 1) != 0; + boolean outDrawCheck2 = (lastStatusDrawableParams & 2) != 0; + boolean outDrawClock = (lastStatusDrawableParams & 4) != 0; + boolean outIsBroadcast = (lastStatusDrawableParams & 16) != 0; + + boolean moveCheckTransition = !outDrawClock && !isBroadcast && !outIsBroadcast && outDrawCheck2 && drawCheck2 && !outDrawCheck1 && drawCheck1; + + if (transitionParams.messageEntering && !moveCheckTransition) { + return; + } + statusDrawableProgress = 0f; + statusDrawableAnimator = ValueAnimator.ofFloat(0,1f); + if (moveCheckTransition) { + statusDrawableAnimator.setDuration(220); + } else { + statusDrawableAnimator.setDuration(150); + } + statusDrawableAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animateFromStatusDrawableParams = lastStatusDrawableParams; + animateToStatusDrawableParams = currentStatus; + statusDrawableAnimator.addUpdateListener(valueAnimator -> { + statusDrawableProgress = (float) valueAnimator.getAnimatedValue(); + invalidate(); + if (fromParent && getParent() != null) { + ((View) getParent()).invalidate(); + } + }); + statusDrawableAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + int currentStatus = transitionParams.createStatusDrawableParams(); + if (animateToStatusDrawableParams != currentStatus) { + createStatusDrawableAnimator(animateToStatusDrawableParams, currentStatus, fromParent); + } else { + statusDrawableAnimationInProgress = false; + transitionParams.lastStatusDrawableParams = animateToStatusDrawableParams; } } - if (drawError) { - int x; - float y; + }); + statusDrawableAnimationInProgress = true; + statusDrawableAnimator.start(); + + } + + private void drawViewsAndRepliesLayout(Canvas canvas, boolean drawTime, boolean drawError, float layoutHeight, float alpha, float timeYOffset, float timeX, float progress, boolean drawSelectionBackground) { + boolean useScale = progress != 1f; + float scale = 0.5f + 0.5f * progress; + alpha *= progress; + if (drawTime) { + if (!currentMessageObject.isOutOwner()) { + Drawable clockDrawable; if (shouldDrawTimeOnMedia()) { - x = layoutWidth - AndroidUtilities.dp(34.5f); - y = layoutHeight - AndroidUtilities.dp(26.5f) + timeYOffset; + clockDrawable = Theme.chat_msgMediaClockDrawable; } else { - x = layoutWidth - AndroidUtilities.dp(32); - y = layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 22 : 21) + timeYOffset; + clockDrawable = drawSelectionBackground ? Theme.chat_msgInSelectedClockDrawable : Theme.chat_msgInClockDrawable; } + float timeY = shouldDrawTimeOnMedia() ? photoImage.getImageY2() + additionalTimeOffsetY - AndroidUtilities.dp(9.0f) : layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9.5f : 8.5f) + timeYOffset; + setDrawableBounds(clockDrawable, timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)), timeY - clockDrawable.getIntrinsicHeight()); + clockDrawable.setAlpha((int) (255 * alpha)); + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, clockDrawable.getBounds().centerX(), clockDrawable.getBounds().centerY()); + } + clockDrawable.draw(canvas); + clockDrawable.setAlpha(255); + invalidate(); + if (useScale) { + canvas.restore(); + } + } + } else if (drawError) { + if (!currentMessageObject.isOutOwner()) { + float x = timeX + (currentMessageObject.scheduled ? 0 : AndroidUtilities.dp(11)); + float y = shouldDrawTimeOnMedia() ? photoImage.getImageY2() + additionalTimeOffsetY - AndroidUtilities.dp(21.5f) : layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 21.5f : 20.5f) + timeYOffset; rect.set(x, y, x + AndroidUtilities.dp(14), y + AndroidUtilities.dp(14)); int oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); - Theme.chat_msgErrorPaint.setAlpha((int) (oldAlpha * alpha)); + Theme.chat_msgErrorPaint.setAlpha((int) (255 * alpha)); + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, rect.centerX(), rect.centerY()); + } canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_msgErrorPaint); Theme.chat_msgErrorPaint.setAlpha(oldAlpha); setDrawableBounds(Theme.chat_msgErrorDrawable, x + AndroidUtilities.dp(6), y + AndroidUtilities.dp(2)); Theme.chat_msgErrorDrawable.setAlpha((int) (255 * alpha)); Theme.chat_msgErrorDrawable.draw(canvas); Theme.chat_msgErrorDrawable.setAlpha(255); + if (useScale) { + canvas.restore(); + } + } + } else { + float offsetX = 0; + int timeAlpha = Theme.chat_timePaint.getAlpha(); + float timeY = shouldDrawTimeOnMedia() ? photoImage.getImageY2() + additionalTimeOffsetY - AndroidUtilities.dp(7.3f) - timeLayout.getHeight() : layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 7.5f : 6.5f) - timeLayout.getHeight() + timeYOffset; + if (repliesLayout != null || transitionParams.animateReplies) { + float repliesX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; + boolean inAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout == null && repliesLayout != null; + boolean outAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout != null && repliesLayout == null; + boolean replaceAnimation = transitionParams.animateReplies && transitionParams.animateRepliesLayout != null && repliesLayout != null; + if (transitionParams.shouldAnimateTimeX && !inAnimation) { + if (outAnimation) { + repliesX = transitionParams.animateFromTimeXReplies; + } else { + repliesX = transitionParams.animateFromTimeXReplies * (1f - transitionParams.animateChangeProgress) + repliesX * transitionParams.animateChangeProgress; + } + } else { + repliesX += transitionParams.deltaRight; + } + if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { + repliesX += currentMessagesGroup.transitionParams.offsetRight; + } + if (transitionParams.animateBackgroundBoundsInner) { + repliesX += animationOffsetX; + } + Drawable repliesDrawable; + if (shouldDrawTimeOnMedia()) { + if (currentMessageObject.shouldDrawWithoutBackground()) { + repliesDrawable = Theme.chat_msgStickerRepliesDrawable; + } else { + repliesDrawable = Theme.chat_msgMediaRepliesDrawable; + } + } else { + if (!currentMessageObject.isOutOwner()) { + repliesDrawable = drawSelectionBackground ? Theme.chat_msgInRepliesSelectedDrawable : Theme.chat_msgInRepliesDrawable; + } else { + repliesDrawable = drawSelectionBackground ? Theme.chat_msgOutRepliesSelectedDrawable : Theme.chat_msgOutRepliesDrawable; + } + } + setDrawableBounds(repliesDrawable, repliesX, timeY); + float repliesAlpha = alpha; + if (inAnimation) { + repliesAlpha *= transitionParams.animateChangeProgress; + } else if (outAnimation) { + repliesAlpha *= (1f - transitionParams.animateChangeProgress); + } + repliesDrawable.setAlpha((int) (255 * repliesAlpha)); + if (useScale) { + canvas.save(); + float cx = repliesX + (repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) + repliesTextWidth) / 2f; + canvas.scale(scale, scale, cx, repliesDrawable.getBounds().centerY()); + } + repliesDrawable.draw(canvas); + repliesDrawable.setAlpha(255); + + if (transitionParams.animateReplies) { + if (replaceAnimation) { + canvas.save(); + Theme.chat_timePaint.setAlpha((int) (timeAlpha * (1.0 - transitionParams.animateChangeProgress))); + canvas.translate(repliesX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) , timeY); + transitionParams.animateRepliesLayout.draw(canvas); + canvas.restore(); + } + Theme.chat_timePaint.setAlpha((int) (timeAlpha * repliesAlpha)); + } + canvas.save(); + canvas.translate(repliesX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), timeY); + if (repliesLayout != null) { + repliesLayout.draw(canvas); + } else if (transitionParams.animateRepliesLayout != null) { + transitionParams.animateRepliesLayout.draw(canvas); + } + canvas.restore(); + if (repliesLayout != null) { + offsetX += repliesDrawable.getIntrinsicWidth() + repliesTextWidth + AndroidUtilities.dp(10); + } + + if (useScale) { + canvas.restore(); + float cx = (repliesX + repliesDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) + repliesTextWidth - repliesX) / 2f; + canvas.scale(scale, scale, cx, repliesDrawable.getBounds().centerY()); + } + + if (transitionParams.animateReplies) { + Theme.chat_timePaint.setAlpha(timeAlpha); + } + transitionParams.lastTimeXReplies = repliesX; + } + if (viewsLayout != null) { + float viewsX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; + if (transitionParams.shouldAnimateTimeX) { + viewsX = transitionParams.animateFromTimeXViews * (1f - transitionParams.animateChangeProgress) + viewsX * transitionParams.animateChangeProgress; + } else { + viewsX += transitionParams.deltaRight; + } + if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { + viewsX += currentMessagesGroup.transitionParams.offsetRight; + } + if (transitionParams.animateBackgroundBoundsInner) { + viewsX += animationOffsetX; + } + Drawable viewsDrawable; + if (shouldDrawTimeOnMedia()) { + if (currentMessageObject.shouldDrawWithoutBackground()) { + viewsDrawable = Theme.chat_msgStickerViewsDrawable; + } else { + viewsDrawable = Theme.chat_msgMediaViewsDrawable; + } + } else { + if (!currentMessageObject.isOutOwner()) { + viewsDrawable = drawSelectionBackground ? Theme.chat_msgInViewsSelectedDrawable : Theme.chat_msgInViewsDrawable; + } else { + viewsDrawable = drawSelectionBackground ? Theme.chat_msgOutViewsSelectedDrawable : Theme.chat_msgOutViewsDrawable; + } + } + float y = shouldDrawTimeOnMedia() ? photoImage.getImageY2() + additionalTimeOffsetY - AndroidUtilities.dp(5.5f) - timeLayout.getHeight() : layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 5.5f : 4.5f) - timeLayout.getHeight() + timeYOffset; + setDrawableBounds(viewsDrawable, viewsX, y); + if (useScale) { + canvas.save(); + float cx = viewsX + (viewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3) + viewsTextWidth) / 2f; + canvas.scale(scale, scale, cx, viewsDrawable.getBounds().centerY()); + } + viewsDrawable.setAlpha((int) (255 * alpha)); + viewsDrawable.draw(canvas); + viewsDrawable.setAlpha(255); + + if (transitionParams.animateViewsLayout != null) { + canvas.save(); + Theme.chat_timePaint.setAlpha((int) (timeAlpha * (1.0 - transitionParams.animateChangeProgress))); + canvas.translate(viewsX + viewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), timeY); + transitionParams.animateViewsLayout.draw(canvas); + canvas.restore(); + Theme.chat_timePaint.setAlpha((int) (timeAlpha * transitionParams.animateChangeProgress)); + } + + canvas.save(); + canvas.translate(viewsX + viewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), timeY); + viewsLayout.draw(canvas); + canvas.restore(); + if (useScale) { + canvas.restore(); + } + + offsetX += viewsTextWidth + Theme.chat_msgInViewsDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); + + if (transitionParams.animateViewsLayout != null) { + Theme.chat_timePaint.setAlpha(timeAlpha); + } + transitionParams.lastTimeXViews = viewsX; + } + if (isPinned || transitionParams.animatePinned) { + float pinnedX = (transitionParams.shouldAnimateTimeX ? this.timeX : timeX) + offsetX; + boolean inAnimation = transitionParams.animatePinned && isPinned; + boolean outAnimation = transitionParams.animatePinned && !isPinned; + if (transitionParams.shouldAnimateTimeX && !inAnimation) { + if (outAnimation) { + pinnedX = transitionParams.animateFromTimeXPinned; + } else { + pinnedX = transitionParams.animateFromTimeXPinned * (1f - transitionParams.animateChangeProgress) + pinnedX * transitionParams.animateChangeProgress; + } + } else { + pinnedX += transitionParams.deltaRight; + } + if (currentMessagesGroup != null && currentMessagesGroup.transitionParams.backgroundChangeBounds) { + pinnedX += currentMessagesGroup.transitionParams.offsetRight; + } + if (transitionParams.animateBackgroundBoundsInner) { + pinnedX += animationOffsetX; + } + + Drawable pinnedDrawable; + if (shouldDrawTimeOnMedia()) { + if (currentMessageObject.shouldDrawWithoutBackground()) { + pinnedDrawable = Theme.chat_msgStickerPinnedDrawable; + } else { + pinnedDrawable = Theme.chat_msgMediaPinnedDrawable; + } + } else { + if (!currentMessageObject.isOutOwner()) { + pinnedDrawable = drawSelectionBackground ? Theme.chat_msgInPinnedSelectedDrawable : Theme.chat_msgInPinnedDrawable; + } else { + pinnedDrawable = drawSelectionBackground ? Theme.chat_msgOutPinnedSelectedDrawable : Theme.chat_msgOutPinnedDrawable; + } + } + if (transitionParams.animatePinned) { + if (isPinned) { + pinnedDrawable.setAlpha((int) (255 * alpha * transitionParams.animateChangeProgress)); + setDrawableBounds(pinnedDrawable, pinnedX, timeY); + } else { + pinnedDrawable.setAlpha((int) (255 * alpha * (1.0f - transitionParams.animateChangeProgress))); + setDrawableBounds(pinnedDrawable, pinnedX, timeY); + } + } else { + pinnedDrawable.setAlpha((int) (255 * alpha)); + setDrawableBounds(pinnedDrawable, pinnedX, timeY); + } + if (useScale) { + canvas.save(); + float cx = pinnedX + pinnedDrawable.getIntrinsicWidth() / 2f; + canvas.scale(scale, scale, cx, pinnedDrawable.getBounds().centerY()); + } + pinnedDrawable.draw(canvas); + pinnedDrawable.setAlpha(255); + + if (isPinned) { + offsetX = pinnedDrawable.getIntrinsicWidth() + AndroidUtilities.dp(6); + } + + if (useScale) { + canvas.restore(); + } + transitionParams.lastTimeXPinned = pinnedX; + } + } + } + + private void drawStatusDrawable(Canvas canvas, boolean drawCheck1, boolean drawCheck2, boolean drawClock, boolean drawError, boolean isBroadcast, float alpha, boolean bigRadius, float timeYOffset, float layoutHeight, float progress, boolean moveCheck, boolean drawSelectionBackground) { + final boolean useScale = progress != 1f && !moveCheck; + float scale = 0.5f + 0.5f * progress; + if (useScale) { + alpha = alpha * progress; + } + float timeY = photoImage.getImageY2() + additionalTimeOffsetY - AndroidUtilities.dp(8.5f); + if (drawClock) { + Drawable drawable; + if (shouldDrawTimeOnMedia()) { + if (currentMessageObject.shouldDrawWithoutBackground()) { + Theme.chat_msgStickerClockDrawable.setAlpha((int) (255 * timeAlpha * alpha)); + setDrawableBounds(Theme.chat_msgStickerClockDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 24 : 22) - Theme.chat_msgStickerClockDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgStickerClockDrawable.getIntrinsicHeight() + timeYOffset); + drawable = Theme.chat_msgStickerClockDrawable; + } else { + setDrawableBounds(Theme.chat_msgMediaClockDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 24 : 22) - Theme.chat_msgMediaClockDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaClockDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgMediaClockDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgMediaClockDrawable; + } + } else { + setDrawableBounds(Theme.chat_msgOutClockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.chat_msgOutClockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - Theme.chat_msgOutClockDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgOutClockDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgOutClockDrawable; + } + + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + drawable.setAlpha(255); + if (useScale) { + canvas.restore(); + } + invalidate(); + } + if (isBroadcast) { + if (drawCheck1 || drawCheck2) { + Drawable drawable; + if (shouldDrawTimeOnMedia()) { + setDrawableBounds(Theme.chat_msgBroadcastMediaDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 26 : 24) - Theme.chat_msgBroadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(14.0f) - Theme.chat_msgBroadcastMediaDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgBroadcastMediaDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgBroadcastMediaDrawable; + } else { + setDrawableBounds(Theme.chat_msgBroadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.chat_msgBroadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.chat_msgBroadcastDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgBroadcastDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgBroadcastDrawable; + } + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + if (useScale) { + canvas.restore(); + } + drawable.setAlpha(255); + } + } else { + if (drawCheck2) { + if (shouldDrawTimeOnMedia()) { + Drawable drawable; + if (moveCheck) { + canvas.save(); + } + if (currentMessageObject.shouldDrawWithoutBackground()) { + if (drawCheck1) { + if (moveCheck) { + canvas.translate(AndroidUtilities.dp(4.8f) * (1f - progress), 0); + } + setDrawableBounds(Theme.chat_msgStickerCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 28.3f : 26.3f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgStickerCheckDrawable.getIntrinsicHeight() + timeYOffset); + } else { + setDrawableBounds(Theme.chat_msgStickerCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgStickerCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgStickerCheckDrawable.getIntrinsicHeight() + timeYOffset); + } + Theme.chat_msgStickerCheckDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgStickerCheckDrawable; + } else { + if (drawCheck1) { + if (moveCheck) { + canvas.translate(AndroidUtilities.dp(4.8f) * (1f - progress), 0); + } + setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 28.3f : 26.3f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); + } else { + setDrawableBounds(Theme.chat_msgMediaCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgMediaCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaCheckDrawable.getIntrinsicHeight() + timeYOffset); + } + Theme.chat_msgMediaCheckDrawable.setAlpha((int) (255 * timeAlpha * alpha)); + drawable = Theme.chat_msgMediaCheckDrawable; + } + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + if (useScale) { + canvas.restore(); + } + if (moveCheck) { + canvas.restore(); + } + drawable.setAlpha(255); + } else { + Drawable drawable; + if (moveCheck) { + canvas.save(); + } + if (drawCheck1) { + if (moveCheck) { + canvas.translate(AndroidUtilities.dp(4) * (1f - progress), 0); + } + drawable = drawSelectionBackground ? Theme.chat_msgOutCheckReadSelectedDrawable : Theme.chat_msgOutCheckReadDrawable; + setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(22.5f) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); + } else { + drawable = drawSelectionBackground ? Theme.chat_msgOutCheckSelectedDrawable : Theme.chat_msgOutCheckDrawable; + setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(18.5f) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); + } + drawable.setAlpha((int) (255 * alpha)); + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + if (useScale) { + canvas.restore(); + } + if (moveCheck) { + canvas.restore(); + } + drawable.setAlpha(255); + } + } + if (drawCheck1) { + if (shouldDrawTimeOnMedia()) { + Drawable drawable; + if (currentMessageObject.shouldDrawWithoutBackground()) { + setDrawableBounds(Theme.chat_msgStickerHalfCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgStickerHalfCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgStickerHalfCheckDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgStickerHalfCheckDrawable.setAlpha((int) (255 * alpha)); + drawable = Theme.chat_msgStickerHalfCheckDrawable; + } else { + setDrawableBounds(Theme.chat_msgMediaHalfCheckDrawable, layoutWidth - AndroidUtilities.dp(bigRadius ? 23.5f : 21.5f) - Theme.chat_msgMediaHalfCheckDrawable.getIntrinsicWidth(), timeY - Theme.chat_msgMediaHalfCheckDrawable.getIntrinsicHeight() + timeYOffset); + Theme.chat_msgMediaHalfCheckDrawable.setAlpha((int) (255 * timeAlpha * alpha)); + drawable = Theme.chat_msgMediaHalfCheckDrawable; + } + if (useScale || moveCheck) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + if (useScale || moveCheck) { + canvas.restore(); + } + drawable.setAlpha(255); + } else { + Drawable drawable = drawSelectionBackground ? Theme.chat_msgOutHalfCheckSelectedDrawable : Theme.chat_msgOutHalfCheckDrawable; + setDrawableBounds(drawable, layoutWidth - AndroidUtilities.dp(18) - drawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 9 : 8) - drawable.getIntrinsicHeight() + timeYOffset); + drawable.setAlpha((int) (255 * alpha)); + if (useScale || moveCheck) { + canvas.save(); + canvas.scale(scale, scale, drawable.getBounds().centerX(), drawable.getBounds().centerY()); + } + drawable.draw(canvas); + if (useScale || moveCheck) { + canvas.restore(); + } + drawable.setAlpha(255); + } + } + } + if (drawError) { + int x; + float y; + if (shouldDrawTimeOnMedia()) { + x = layoutWidth - AndroidUtilities.dp(34.5f); + y = layoutHeight - AndroidUtilities.dp(26.5f) + timeYOffset; + } else { + x = layoutWidth - AndroidUtilities.dp(32); + y = layoutHeight - AndroidUtilities.dp(pinnedBottom || pinnedTop ? 22 : 21) + timeYOffset; + } + rect.set(x, y, x + AndroidUtilities.dp(14), y + AndroidUtilities.dp(14)); + int oldAlpha = Theme.chat_msgErrorPaint.getAlpha(); + Theme.chat_msgErrorPaint.setAlpha((int) (oldAlpha * alpha)); + canvas.drawRoundRect(rect, AndroidUtilities.dp(1), AndroidUtilities.dp(1), Theme.chat_msgErrorPaint); + Theme.chat_msgErrorPaint.setAlpha(oldAlpha); + setDrawableBounds(Theme.chat_msgErrorDrawable, x + AndroidUtilities.dp(6), y + AndroidUtilities.dp(2)); + Theme.chat_msgErrorDrawable.setAlpha((int) (255 * alpha)); + if (useScale) { + canvas.save(); + canvas.scale(scale, scale, Theme.chat_msgErrorDrawable.getBounds().centerX(), Theme.chat_msgErrorDrawable.getBounds().centerY()); + } + Theme.chat_msgErrorDrawable.draw(canvas); + Theme.chat_msgErrorDrawable.setAlpha(255); + if (useScale) { + canvas.restore(); } } } @@ -11047,7 +11685,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (!currentMessageObject.needDrawBluredPreview()) { if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { int oldAlpha = ((BitmapDrawable) Theme.chat_msgMediaMenuDrawable).getPaint().getAlpha(); - if (drawPhotoCheckBox) { + if (drawMediaCheckBox) { Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha * (1.0f - checkBoxAnimationProgress))); } else { Theme.chat_msgMediaMenuDrawable.setAlpha((int) (oldAlpha * controlsAlpha)); @@ -11230,9 +11868,24 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeoLive) { int cy = (int) (photoImage.getImageY2() + AndroidUtilities.dp(30)); - if (!locationExpired) { + if (!locationExpired || transitionParams.animateLocationIsExpired) { forceNotDrawTime = true; - float progress = 1.0f - Math.abs(ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date) / (float) currentMessageObject.messageOwner.media.period; + float progress; + String text; + StaticLayout docTitleLayout = this.docTitleLayout; + StaticLayout infoLayout = this.infoLayout; + float alpha = 1f; + if (transitionParams.animateLocationIsExpired){ + progress = transitionParams.lastDrawLocationExpireProgress; + text = transitionParams.lastDrawLocationExpireText; + docTitleLayout = transitionParams.lastDrawDocTitleLayout; + infoLayout = transitionParams.lastDrawInfoLayout; + alpha = 1f - transitionParams.animateChangeProgress; + } else { + progress = 1.0f - Math.abs(ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date) / (float) currentMessageObject.messageOwner.media.period; + text = LocaleController.formatLocationLeftTime(Math.abs(currentMessageObject.messageOwner.media.period - (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date))); + } + rect.set(photoImage.getImageX2() - AndroidUtilities.dp(43), cy - AndroidUtilities.dp(15), photoImage.getImageX2() - AndroidUtilities.dp(13), cy + AndroidUtilities.dp(15)); if (currentMessageObject.isOutOwner()) { Theme.chat_radialProgress2Paint.setColor(Theme.getColor(Theme.key_chat_outInstant)); @@ -11242,22 +11895,49 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate Theme.chat_livePaint.setColor(Theme.getColor(Theme.key_chat_inInstant)); } - Theme.chat_radialProgress2Paint.setAlpha(50); + int docTitleAlpha = Theme.chat_locationTitlePaint.getAlpha(); + int infoAlpha = Theme.chat_locationAddressPaint.getAlpha(); + int liveAplha = Theme.chat_livePaint.getAlpha(); + if (alpha != 1f) { + Theme.chat_locationTitlePaint.setAlpha((int) (docTitleAlpha * alpha)); + Theme.chat_locationAddressPaint.setAlpha((int) (infoAlpha * alpha)); + Theme.chat_livePaint.setAlpha((int) (liveAplha * alpha)); + canvas.save(); + canvas.translate(0, -AndroidUtilities.dp(50) * transitionParams.animateChangeProgress); + } + + Theme.chat_radialProgress2Paint.setAlpha((int) (50 * alpha)); canvas.drawCircle(rect.centerX(), rect.centerY(), AndroidUtilities.dp(15), Theme.chat_radialProgress2Paint); - Theme.chat_radialProgress2Paint.setAlpha(255); + Theme.chat_radialProgress2Paint.setAlpha((int) (255 * alpha)); canvas.drawArc(rect, -90, -360 * progress, false, Theme.chat_radialProgress2Paint); - String text = LocaleController.formatLocationLeftTime(Math.abs(currentMessageObject.messageOwner.media.period - (ConnectionsManager.getInstance(currentAccount).getCurrentTime() - currentMessageObject.messageOwner.date))); float w = Theme.chat_livePaint.measureText(text); - canvas.drawText(text, rect.centerX() - w / 2, cy + AndroidUtilities.dp(4), Theme.chat_livePaint); - canvas.save(); - canvas.translate(photoImage.getImageX() + AndroidUtilities.dp(10), photoImage.getImageY2() + AndroidUtilities.dp(10)); - docTitleLayout.draw(canvas); - canvas.translate(0, AndroidUtilities.dp(23)); - infoLayout.draw(canvas); - canvas.restore(); + if (docTitleLayout != null && infoLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + AndroidUtilities.dp(10), photoImage.getImageY2() + AndroidUtilities.dp(10)); + docTitleLayout.draw(canvas); + canvas.translate(0, AndroidUtilities.dp(23)); + infoLayout.draw(canvas); + canvas.restore(); + } + + if (alpha != 1f) { + Theme.chat_locationTitlePaint.setAlpha(docTitleAlpha); + Theme.chat_locationAddressPaint.setAlpha(infoAlpha); + Theme.chat_livePaint.setAlpha(liveAplha); + canvas.restore(); + } + + transitionParams.lastDrawLocationExpireProgress = progress; + transitionParams.lastDrawLocationExpireText = text; + transitionParams.lastDrawDocTitleLayout = docTitleLayout; + transitionParams.lastDrawInfoLayout = infoLayout; + } else { + transitionParams.lastDrawLocationExpireText = null; + transitionParams.lastDrawDocTitleLayout = null; + transitionParams.lastDrawInfoLayout = null; } int cx = (int) (photoImage.getImageX() + photoImage.getImageWidth() / 2 - AndroidUtilities.dp(31)); @@ -11336,7 +12016,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate otherY = AndroidUtilities.dp(18.5f); } else if (pinnedBottom && pinnedTop) { otherY = AndroidUtilities.dp(18); - } else if (!pinnedBottom && pinnedTop) { + } else if (!pinnedBottom) { otherY = AndroidUtilities.dp(17); } else { otherY = AndroidUtilities.dp(19); @@ -11730,11 +12410,21 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } videoRadialProgress.draw(canvas); } - if (drawPhotoCheckBox) { - int size = AndroidUtilities.dp(21); - photoCheckBox.setColor(null, null, currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected); - photoCheckBox.setBounds((int) photoImage.getImageX2() - AndroidUtilities.dp(21 + 4), (int) photoImage.getImageY() + AndroidUtilities.dp(4), size, size); - photoCheckBox.draw(canvas); + if (drawMediaCheckBox) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { + int size = AndroidUtilities.dp(20); + mediaCheckBox.setBackgroundType(radialProgress.getMiniIcon() != MediaActionDrawable.ICON_NONE ? 12 : 13); + mediaCheckBox.setBounds(buttonX + AndroidUtilities.dp(28), buttonY + AndroidUtilities.dp(28), size, size); + mediaCheckBox.setColor(currentMessageObject.isOutOwner() ? Theme.key_chat_outTimeText : Theme.key_chat_inTimeText, currentMessageObject.isOutOwner() ? Theme.key_chat_outLoader : Theme.key_chat_inLoader, currentMessageObject.isOutOwner() ? Theme.key_chat_outBubble : Theme.key_chat_inBubble); + mediaCheckBox.setBackgroundDrawable(isDrawSelectionBackground() ? currentBackgroundSelectedDrawable : currentBackgroundDrawable); + } else { + int size = AndroidUtilities.dp(21); + mediaCheckBox.setBackgroundType(0); + mediaCheckBox.setBounds((int) photoImage.getImageX2() - AndroidUtilities.dp(21 + 4), (int) photoImage.getImageY() + AndroidUtilities.dp(4), size, size); + mediaCheckBox.setColor(null, null, currentMessageObject.isOutOwner() ? Theme.key_chat_outBubbleSelected : Theme.key_chat_inBubbleSelected); + mediaCheckBox.setBackgroundDrawable(null); + } + mediaCheckBox.draw(canvas); } } @@ -11751,6 +12441,26 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_ROUND || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF ? documentAttach : null; } + public boolean drawPinnedBottom() { + if (currentMessagesGroup != null && currentMessagesGroup.isDocuments) { + if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + return pinnedBottom; + } + return true; + } + return pinnedBottom; + } + + public boolean drawPinnedTop() { + if (currentMessagesGroup != null && currentMessagesGroup.isDocuments) { + if (currentPosition != null && (currentPosition.flags & MessageObject.POSITION_FLAG_TOP) != 0) { + return pinnedTop; + } + return true; + } + return pinnedTop; + } + public boolean isPinnedBottom() { return pinnedBottom; } @@ -11918,11 +12628,11 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } public int computeHeight(MessageObject object, MessageObject.GroupedMessages groupedMessages) { - if (object.type == 2 || object.type == 12 || object.type == 9 || + /*if (object.type == 2 || object.type == 12 || object.type == 9 || object.type == 4 || object.type == 14 || object.type == 10 || object.type == 11 || object.type == MessageObject.TYPE_ROUND_VIDEO) { return object.getApproximateHeight(); - } + }*/ photoImage.setIgnoreImageSet(true); avatarImage.setIgnoreImageSet(true); replyImageReceiver.setIgnoreImageSet(true); @@ -12534,28 +13244,58 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate return transitionParams; } + public int getTopMediaOffset() { + if (currentMessageObject != null && currentMessageObject.type == 14) { + return mediaOffsetY + namesOffset; + } + return 0; + } + public class TransitionParams { public float lastDrawingImageX, lastDrawingImageY, lastDrawingImageW, lastDrawingImageH; public float lastDrawingCaptionX, lastDrawingCaptionY; + public boolean animateChange; + public int animateFromRepliesTextWidth; + public boolean messageEntering; + public boolean animateLocationIsExpired; + public boolean lastLocatinIsExpired; + public String lastDrawLocationExpireText; + public float lastDrawLocationExpireProgress; + public StaticLayout lastDrawDocTitleLayout; + public StaticLayout lastDrawInfoLayout; + + private boolean lastIsPinned; + private boolean animatePinned; + public float lastTimeXPinned; + public float animateFromTimeXPinned; private int lastRepliesCount; private boolean animateReplies; private StaticLayout lastRepliesLayout; private StaticLayout animateRepliesLayout; + private float animateFromTimeXReplies; + private float lastTimeXReplies; + + private float animateFromTimeXViews; + private float lastTimeXViews; private int lastCommentsCount; private int lastTotalCommentWidth; private int lastCommentArrowX; private int lastCommentUnreadX; private boolean lastCommentDrawUnread; + private float lastCommentX; + private boolean lastDrawCommentNumber; private StaticLayout lastCommentLayout; private boolean animateComments; private StaticLayout animateCommentsLayout; + private float animateCommentX; private int animateTotalCommentWidth; private int animateCommentArrowX; private int animateCommentUnreadX; private boolean animateCommentDrawUnread; + private boolean animateDrawCommentNumber; private boolean animateSign; private float animateNameX; @@ -12591,11 +13331,17 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private boolean animateEditedEnter; private StaticLayout animateEditedLayout; private StaticLayout animateTimeLayout; + private int animateTimeWidth; + private int lastTimeWidth; private boolean lastDrawingEdited; boolean animateReplaceCaptionLayout; private StaticLayout animateOutCaptionLayout; private StaticLayout lastDrawingCaptionLayout; + public boolean lastDrawTime; + public int lastTimeX; + public int animateFromTimeX; + public boolean shouldAnimateTimeX; public boolean animateDrawingTimeAlpha; @@ -12609,6 +13355,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate private float animateFromButtonY; private boolean animateButton; + public int lastStatusDrawableParams = -1; + + private int lastViewsCount; + private StaticLayout lastViewsLayout; + private StaticLayout animateViewsLayout; + + private boolean lastShouldDrawTimeOnMedia; + private boolean animateShouldDrawTimeOnMedia; + private boolean lastShouldDrawMenuDrawable; + private boolean animateShouldDrawMenuDrawable; + private StaticLayout lastTimeLayout; + + public int lastTopOffset; + public void recordDrawingState() { wasDraw = true; lastDrawingImageX = photoImage.getImageX(); @@ -12639,16 +13399,32 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate lastCommentArrowX = commentArrowX; lastCommentUnreadX = commentUnreadX; lastCommentDrawUnread = commentDrawUnread; + lastCommentX = commentX; + lastDrawCommentNumber = drawCommentNumber; } - if (repliesLayout != null) { - lastRepliesCount = getRepliesCount(); - lastRepliesLayout = repliesLayout; - } + + lastRepliesCount = getRepliesCount(); + this.lastViewsCount = getMessageObject().messageOwner.views; + lastRepliesLayout = repliesLayout; + lastViewsLayout = viewsLayout; + + lastIsPinned = isPinned; lastSignMessage = lastPostAuthor; lastButtonX = buttonX; lastButtonY = buttonY; + + lastDrawTime = !forceNotDrawTime; + lastTimeX = timeX; + lastTimeLayout = timeLayout; + lastTimeWidth = timeWidth; + + lastShouldDrawTimeOnMedia = shouldDrawTimeOnMedia(); + lastTopOffset = getTopMediaOffset(); + lastShouldDrawMenuDrawable = shouldDrawMenuDrawable(); + + lastLocatinIsExpired = locationExpired; } public boolean animateChange() { @@ -12668,13 +13444,20 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate String text = timeLayout.getText().toString(); int i = text.indexOf(editedStr); if (i >= 0) { - animateEditedLayout = new StaticLayout(editedStr, Theme.chat_timePaint, timeTextWidth + AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); - spannableStringBuilder.append(editedStr); - spannableStringBuilder.append(text.substring(editedStr.length())); - spannableStringBuilder.setSpan(new EmptyStubSpan(), 0, editedStr.length(), 0); - animateTimeLayout = new StaticLayout(spannableStringBuilder, Theme.chat_timePaint, timeTextWidth + AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (i == 0) { + animateEditedLayout = new StaticLayout(editedStr, Theme.chat_timePaint, timeTextWidth + AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + spannableStringBuilder.append(editedStr); + spannableStringBuilder.append(text.substring(editedStr.length())); + spannableStringBuilder.setSpan(new EmptyStubSpan(), 0, editedStr.length(), 0); + animateTimeLayout = new StaticLayout(spannableStringBuilder, Theme.chat_timePaint, timeTextWidth + AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } else { + animateEditedLayout = null; + animateTimeLayout = lastTimeLayout; + } animateEditedEnter = true; + animateTimeWidth = lastTimeWidth; + animateFromTimeX = lastTimeX; changed = true; } } @@ -12682,8 +13465,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate if (captionLayout != lastDrawingCaptionLayout) { String oldCaption = lastDrawingCaptionLayout == null ? null : lastDrawingCaptionLayout.getText().toString(); String currentCaption = captionLayout == null ? null : captionLayout.getText().toString(); - if (currentCaption != null && ((oldCaption == null && currentCaption != null) || - !oldCaption.equals(currentCaption))) { + if (currentCaption != null && (oldCaption == null || !oldCaption.equals(currentCaption))) { animateReplaceCaptionLayout = true; animateOutCaptionLayout = lastDrawingCaptionLayout; changed = true; @@ -12701,7 +13483,7 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate transitionBotButtons.addAll(lastDrawBotButtons); } - if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { if (buttonX != lastButtonX || buttonY != lastButtonY) { animateFromButtonX = lastButtonX; animateFromButtonY = lastButtonY; @@ -12710,18 +13492,39 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate } } - if (repliesLayout != null && lastRepliesCount != getRepliesCount()) { + boolean timeDrawablesIsChanged = false; + + if (lastIsPinned != isPinned) { + animatePinned = true; + changed = true; + timeDrawablesIsChanged = true; + } + + if ((lastRepliesLayout != null || repliesLayout != null) && lastRepliesCount != getRepliesCount()) { animateRepliesLayout = lastRepliesLayout; animateReplies = true; changed = true; + timeDrawablesIsChanged = true; + } + + if (lastViewsLayout != null && this.lastViewsCount != getMessageObject().messageOwner.views) { + animateViewsLayout = lastViewsLayout; + changed = true; + timeDrawablesIsChanged = true; } if (commentLayout != null && lastCommentsCount != getRepliesCount()) { - animateCommentsLayout = lastCommentLayout; + if (lastCommentLayout != null && !TextUtils.equals(lastCommentLayout.getText(), commentLayout.getText())) { + animateCommentsLayout = lastCommentLayout; + } else { + animateCommentsLayout = null; + } animateTotalCommentWidth = lastTotalCommentWidth; + animateCommentX = lastCommentX; animateCommentArrowX = lastCommentArrowX; animateCommentUnreadX = lastCommentUnreadX; animateCommentDrawUnread = lastCommentDrawUnread; + animateDrawCommentNumber = lastDrawCommentNumber; animateComments = true; changed = true; } @@ -12732,15 +13535,43 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate changed = true; } + if (lastDrawTime == forceNotDrawTime) { + animateDrawingTimeAlpha = true; + animateViewsLayout = null; + changed = true; + } else if (lastShouldDrawTimeOnMedia != shouldDrawTimeOnMedia()) { + animateEditedEnter = false; + animateShouldDrawTimeOnMedia = true; + animateFromTimeX = lastTimeX; + animateTimeLayout = lastTimeLayout; + animateTimeWidth = lastTimeWidth; + changed = true; + } else if (timeDrawablesIsChanged || timeX != lastTimeX) { + shouldAnimateTimeX = true; + animateTimeWidth = lastTimeWidth; + animateFromTimeX = lastTimeX; + animateFromTimeXViews = lastTimeXViews; + animateFromTimeXReplies = lastTimeXReplies; + animateFromTimeXPinned = lastTimeXPinned; + } + + if (lastShouldDrawMenuDrawable != shouldDrawMenuDrawable()) { + animateShouldDrawMenuDrawable = true; + } + + if (lastLocatinIsExpired != locationExpired) { + animateLocationIsExpired = true; + } return changed; } public void onDetach() { wasDraw = false; - // resetAnimation(); } public void resetAnimation() { + animateChange = false; + animatePinned = false; animateBackgroundBoundsInner = false; deltaLeft = 0; deltaRight = 0; @@ -12779,12 +13610,52 @@ public class ChatMessageCell extends BaseCell implements SeekBar.SeekBarDelegate animateComments = false; animateCommentsLayout = null; - + animateViewsLayout = null; + animateShouldDrawTimeOnMedia = false; + animateShouldDrawMenuDrawable = false; + shouldAnimateTimeX = false; animateSign = false; + animateDrawingTimeAlpha = false; + animateLocationIsExpired = false; } public boolean supportChangeAnimation() { return true; } + + public int createStatusDrawableParams() { + if (currentMessageObject.isOutOwner()) { + boolean drawCheck1 = false; + boolean drawCheck2 = false; + boolean drawClock = false; + boolean drawError = false; + boolean isBroadcast = (int) (currentMessageObject.getDialogId() >> 32) == 1; + + if (currentMessageObject.isSending() || currentMessageObject.isEditing()) { + drawCheck2 = false; + drawClock = true; + drawError = false; + } else if (currentMessageObject.isSendError()) { + drawCheck2 = false; + drawClock = false; + drawError = true; + } else if (currentMessageObject.isSent()) { + if (!currentMessageObject.scheduled && !currentMessageObject.isUnread()) { + drawCheck1 = true; + } else { + drawCheck1 = false; + } + drawCheck2 = true; + drawClock = false; + drawError = false; + } + return (drawCheck1 ? 1 : 0) | (drawCheck2 ? 2 : 0) | (drawClock ? 4 : 0) | (drawError ? 8 : 0) | (isBroadcast ? 16 : 0); + } else { + boolean drawClock = currentMessageObject.isSending() || currentMessageObject.isEditing(); + boolean drawError = currentMessageObject.isSendError(); + + return (drawClock ? 4 : 0) | (drawError ? 8 : 0); + } + } } } 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 5428e94e8..6ffdaeab4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -8,6 +8,9 @@ package org.telegram.ui.Cells; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; @@ -23,7 +26,6 @@ import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; -import android.text.style.ForegroundColorSpan; import android.text.style.ReplacementSpan; import android.view.HapticFeedbackConstants; import android.view.accessibility.AccessibilityEvent; @@ -52,13 +54,17 @@ import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.ImageReceiver; import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.EmptyStubSpan; +import org.telegram.ui.Components.ForegroundColorSpanThemable; import org.telegram.ui.Components.PullForegroundDrawable; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.CheckBox2; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.RLottieDrawable; import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.Components.StatusDrawable; import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.TypingDotsDrawable; import org.telegram.ui.DialogsActivity; import java.util.ArrayList; @@ -164,6 +170,7 @@ public class DialogCell extends BaseCell { private TLRPC.Chat chat; private TLRPC.EncryptedChat encryptedChat; private CharSequence lastPrintString; + private int printingStringType; private TLRPC.DraftMessage draftMessage; private CheckBox2 checkBox; @@ -195,6 +202,8 @@ public class DialogCell extends BaseCell { private boolean drawCheck2; private boolean drawClock; private int checkDrawLeft; + private int checkDrawLeft1; + private int clockDrawLeft; private int checkDrawTop; private int halfCheckDrawLeft; @@ -238,6 +247,13 @@ public class DialogCell extends BaseCell { private RectF rect = new RectF(); + private int animateToStatusDrawableParams; + private int animateFromStatusDrawableParams; + private int lastStatusDrawableParams = -1; + private float statusDrawableProgress; + private boolean statusDrawableAnimationInProgress; + private ValueAnimator statusDrawableAnimator; + public static class BounceInterpolator implements Interpolator { public float getInterpolation(float t) { @@ -278,6 +294,14 @@ public class DialogCell extends BaseCell { } public void setDialog(TLRPC.Dialog dialog, int type, int folder) { + if (currentDialogId != dialog.id) { + if (statusDrawableAnimator != null) { + statusDrawableAnimator.removeAllListeners(); + statusDrawableAnimator.cancel(); + } + statusDrawableAnimationInProgress = false; + lastStatusDrawableParams = -1; + } currentDialogId = dialog.id; isDialogCell = true; if (dialog instanceof TLRPC.TL_dialogFolder) { @@ -313,6 +337,9 @@ public class DialogCell extends BaseCell { } public void setDialog(long dialog_id, MessageObject messageObject, int date, boolean useMe) { + if (currentDialogId != dialog_id) { + lastStatusDrawableParams = -1; + } currentDialogId = dialog_id; message = messageObject; useMeForMyMessages = useMe; @@ -464,6 +491,7 @@ public class DialogCell extends BaseCell { return Emoji.replaceEmoji(builder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(17), false); } + public void buildLayout() { int thumbSize; if (useForceThreeLines || SharedConfig.useThreeLinesLayout) { @@ -495,7 +523,7 @@ public class DialogCell extends BaseCell { CharSequence messageNameString = null; CharSequence printingString = null; if (isDialogCell) { - printingString = MessagesController.getInstance(currentAccount).getPrintingString(currentDialogId, 0); + printingString = MessagesController.getInstance(currentAccount).getPrintingString(currentDialogId, 0, true); } TextPaint currentMessagePaint = Theme.dialogs_messagePaint[paintIndex]; boolean checkMessage = true; @@ -511,6 +539,7 @@ public class DialogCell extends BaseCell { int offsetName = 0; boolean showChecks = !UserObject.isUserSelf(user) && !useMeForMyMessages; boolean drawTime = true; + printingStringType = -1; String messageFormat; boolean hasNameInMessage; @@ -603,7 +632,7 @@ public class DialogCell extends BaseCell { if (customDialog.isMedia) { currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; stringBuilder = SpannableStringBuilder.valueOf(String.format(messageFormat, message.messageText)); - stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_attachMessage)), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_attachMessage), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } else { String mess = customDialog.message; if (mess.length() > 150) { @@ -774,8 +803,18 @@ public class DialogCell extends BaseCell { } if (printingString != null) { - lastPrintString = messageString = printingString; + lastPrintString = printingString; + printingStringType = MessagesController.getInstance(currentAccount).getPrintingStringType(currentDialogId, 0); + StatusDrawable statusDrawable = Theme.getChatStatusDrawable(printingStringType); + int startPadding = 0; + if (statusDrawable != null) { + startPadding = statusDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3); + } + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); + spannableStringBuilder.append(" ").append(TextUtils.replace(printingString, new String[]{"..."}, new String[]{""})).setSpan(new FixedWidthSpan(startPadding), 0, 1, 0); + messageString = spannableStringBuilder; currentMessagePaint = Theme.dialogs_messagePrintingPaint[paintIndex]; + checkMessage = false; } else { lastPrintString = null; if (draftMessage != null) { @@ -786,7 +825,7 @@ public class DialogCell extends BaseCell { messageString = ""; } else { SpannableStringBuilder stringBuilder = SpannableStringBuilder.valueOf(messageNameString); - stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_draft)), 0, messageNameString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_draft), 0, messageNameString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); messageString = stringBuilder; } } else { @@ -796,7 +835,7 @@ public class DialogCell extends BaseCell { } SpannableStringBuilder stringBuilder = SpannableStringBuilder.valueOf(String.format(messageFormat, mess.replace('\n', ' '), messageNameString)); if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout) { - stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_draft)), 0, messageNameString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_draft), 0, messageNameString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } messageString = Emoji.replaceEmoji(stringBuilder, Theme.dialogs_messagePaint[paintIndex].getFontMetricsInt(), AndroidUtilities.dp(20), false); } @@ -821,7 +860,13 @@ public class DialogCell extends BaseCell { } } } else { - messageString = ""; + if (dialogsType == 3 && UserObject.isUserSelf(user)) { + messageString = LocaleController.getString("SavedMessagesInfo", R.string.SavedMessagesInfo); + showChecks = false; + drawTime = false; + } else { + messageString = ""; + } } } else { TLRPC.User fromUser = null; @@ -877,7 +922,7 @@ public class DialogCell extends BaseCell { } } } - if (chat != null && chat.id > 0 && fromChat == null) { + if (chat != null && chat.id > 0 && fromChat == null && (!ChatObject.isChannel(chat) || ChatObject.isMegagroup(chat))) { if (message.isOutOwner()) { messageNameString = LocaleController.getString("FromYou", R.string.FromYou); } else if (fromUser != null) { @@ -945,14 +990,16 @@ public class DialogCell extends BaseCell { innerMessage = innerMessage.replace('\n', ' '); stringBuilder = SpannableStringBuilder.valueOf(String.format(messageFormat, innerMessage, messageNameString)); try { - stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_attachMessage)), hasNameInMessage ? messageNameString.length() + 2 : 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_attachMessage), hasNameInMessage ? messageNameString.length() + 2 : 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } catch (Exception e) { FileLog.e(e); } } else if (message.messageOwner.message != null) { String mess = message.messageOwner.message; if (message.hasHighlightedWords()) { - mess = mess.replace('\n', ' ').replaceAll(" +", " ").trim(); + if (message.messageTrimmedToHighlight != null) { + mess = message.messageTrimmedToHighlight; + } int w = getMeasuredWidth() - AndroidUtilities.dp(72 + 23 + 10); if (hasNameInMessage) { if (!TextUtils.isEmpty(messageNameString)) { @@ -961,7 +1008,7 @@ public class DialogCell extends BaseCell { w -= currentMessagePaint.measureText(": "); } if (w > 0) { - mess = AndroidUtilities.ellipsizeCenterEnd(mess, message.highlightedWords.get(0), w, currentMessagePaint).toString(); + mess = AndroidUtilities.ellipsizeCenterEnd(mess, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); } } else { if (mess.length() > 150) { @@ -976,7 +1023,7 @@ public class DialogCell extends BaseCell { int thumbInsertIndex = 0; if (!useForceThreeLines && !SharedConfig.useThreeLinesLayout || currentDialogFolderId != 0 && stringBuilder.length() > 0) { try { - stringBuilder.setSpan(new ForegroundColorSpan(Theme.getColor(Theme.key_chats_nameMessage)), 0, thumbInsertIndex = messageNameString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new ForegroundColorSpanThemable(Theme.key_chats_nameMessage), 0, thumbInsertIndex = messageNameString.length() + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); offsetName = thumbInsertIndex; } catch (Exception e) { FileLog.e(e); @@ -1019,7 +1066,10 @@ public class DialogCell extends BaseCell { emoji = "\uD83D\uDCCE "; } if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { - String str = message.messageOwner.message.replace('\n', ' ').replaceAll(" +", " ").trim(); + String str = message.messageTrimmedToHighlight; + if (message.messageTrimmedToHighlight != null) { + str = message.messageTrimmedToHighlight; + } int w = getMeasuredWidth() - AndroidUtilities.dp(72 + 23 + 24); if (hasNameInMessage) { if (!TextUtils.isEmpty(messageNameString)) { @@ -1028,7 +1078,7 @@ public class DialogCell extends BaseCell { w -= currentMessagePaint.measureText(": "); } if (w > 0) { - str = AndroidUtilities.ellipsizeCenterEnd(str, message.highlightedWords.get(0), w, currentMessagePaint).toString(); + str = AndroidUtilities.ellipsizeCenterEnd(str, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); } messageString = emoji + str; } else { @@ -1044,9 +1094,12 @@ public class DialogCell extends BaseCell { messageString = String.format("\uD83C\uDFA7 %s - %s", message.getMusicAuthor(), message.getMusicTitle()); } else { if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)){ - messageString = message.messageOwner.message.replace('\n', ' ').trim(); + messageString = message.messageTrimmedToHighlight; + if (message.messageTrimmedToHighlight != null) { + messageString = message.messageTrimmedToHighlight; + } int w = getMeasuredWidth() - AndroidUtilities.dp(72 + 23 ); - messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint).toString(); + messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); } else { messageString = message.messageText; } @@ -1058,9 +1111,12 @@ public class DialogCell extends BaseCell { } if (hasMessageThumb) { if (message.hasHighlightedWords() && !TextUtils.isEmpty(message.messageOwner.message)) { - messageString = message.messageOwner.message.replace('\n', ' ').replaceAll(" +", " ").trim(); + messageString = message.messageTrimmedToHighlight; + if (message.messageTrimmedToHighlight != null) { + messageString = message.messageTrimmedToHighlight; + } int w = getMeasuredWidth() - AndroidUtilities.dp(72 + 23 + thumbSize + 6); - messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint).toString(); + messageString = AndroidUtilities.ellipsizeCenterEnd(messageString, message.highlightedWords.get(0), w, currentMessagePaint, 130).toString(); } else { if (messageString.length() > 150) { messageString = messageString.subSequence(0, 150); @@ -1252,9 +1308,9 @@ public class DialogCell extends BaseCell { int w = Theme.dialogs_clockDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); nameWidth -= w; if (!LocaleController.isRTL) { - checkDrawLeft = timeLeft - w; + clockDrawLeft = timeLeft - w; } else { - checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(5); + clockDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(5); nameLeft += w; } } else if (drawCheck2) { @@ -1272,9 +1328,9 @@ public class DialogCell extends BaseCell { } } else { if (!LocaleController.isRTL) { - checkDrawLeft = timeLeft - w; + checkDrawLeft1 = timeLeft - w; } else { - checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(5); + checkDrawLeft1 = timeLeft + timeWidth + AndroidUtilities.dp(5); nameLeft += w; } } @@ -1594,6 +1650,71 @@ public class DialogCell extends BaseCell { } } + private void drawCheckStatus(Canvas canvas, boolean drawClock, boolean drawCheck1, boolean drawCheck2, boolean moveCheck, float alpha) { + float scale = 0.5f + 0.5f * alpha; + if (drawClock) { + setDrawableBounds(Theme.dialogs_clockDrawable, clockDrawLeft, checkDrawTop); + if (alpha != 1f) { + canvas.save(); + canvas.scale(scale, scale, Theme.dialogs_clockDrawable.getBounds().centerX(), Theme.dialogs_halfCheckDrawable.getBounds().centerY()); + Theme.dialogs_clockDrawable.setAlpha((int) (255 * alpha)); + } + Theme.dialogs_clockDrawable.draw(canvas); + if (alpha != 1f) { + canvas.restore(); + Theme.dialogs_clockDrawable.setAlpha(255); + } + invalidate(); + } else if (drawCheck2) { + if (drawCheck1) { + setDrawableBounds(Theme.dialogs_halfCheckDrawable, halfCheckDrawLeft, checkDrawTop); + if (moveCheck) { + canvas.save(); + canvas.scale(scale, scale, Theme.dialogs_halfCheckDrawable.getBounds().centerX(), Theme.dialogs_halfCheckDrawable.getBounds().centerY()); + Theme.dialogs_halfCheckDrawable.setAlpha((int) (255 * alpha)); + } + if (!moveCheck && alpha != 0) { + canvas.save(); + canvas.scale(scale, scale, Theme.dialogs_halfCheckDrawable.getBounds().centerX(), Theme.dialogs_halfCheckDrawable.getBounds().centerY()); + Theme.dialogs_halfCheckDrawable.setAlpha((int) (255 * alpha)); + Theme.dialogs_checkReadDrawable.setAlpha((int) (255 * alpha)); + } + + Theme.dialogs_halfCheckDrawable.draw(canvas); + + if (moveCheck) { + canvas.restore(); + canvas.save(); + canvas.translate(AndroidUtilities.dp(4) * (1f - alpha), 0); + } + setDrawableBounds(Theme.dialogs_checkReadDrawable, checkDrawLeft, checkDrawTop); + Theme.dialogs_checkReadDrawable.draw(canvas); + if (moveCheck) { + canvas.restore(); + Theme.dialogs_halfCheckDrawable.setAlpha(255); + } + + if (!moveCheck && alpha != 0) { + canvas.restore(); + Theme.dialogs_halfCheckDrawable.setAlpha(255); + Theme.dialogs_checkReadDrawable.setAlpha(255); + } + } else { + setDrawableBounds(Theme.dialogs_checkDrawable, checkDrawLeft1, checkDrawTop); + if (alpha != 1f) { + canvas.save(); + canvas.scale(scale, scale, Theme.dialogs_checkDrawable.getBounds().centerX(), Theme.dialogs_halfCheckDrawable.getBounds().centerY()); + Theme.dialogs_checkDrawable.setAlpha((int) (255 * alpha)); + } + Theme.dialogs_checkDrawable.draw(canvas); + if (alpha != 1f) { + canvas.restore(); + Theme.dialogs_checkDrawable.setAlpha(255); + } + } + } + } + public boolean isPointInsideAvatar(float x, float y) { if (!LocaleController.isRTL) { return x >= 0 && x < AndroidUtilities.dp(60); @@ -1751,7 +1872,7 @@ public class DialogCell extends BaseCell { } if (isDialogCell) { if ((mask & MessagesController.UPDATE_MASK_USER_PRINT) != 0) { - CharSequence printString = MessagesController.getInstance(currentAccount).getPrintingString(currentDialogId, 0); + CharSequence printString = MessagesController.getInstance(currentAccount).getPrintingString(currentDialogId, 0, true); if (lastPrintString != null && printString == null || lastPrintString == null && printString != null || lastPrintString != null && printString != null && !lastPrintString.equals(printString)) { continueUpdate = true; } @@ -2188,25 +2309,54 @@ public class DialogCell extends BaseCell { FileLog.e(e); } canvas.restore(); - } - if (currentDialogFolderId == 0) { - if (drawClock) { - setDrawableBounds(Theme.dialogs_clockDrawable, checkDrawLeft, checkDrawTop); - Theme.dialogs_clockDrawable.draw(canvas); - } else if (drawCheck2) { - if (drawCheck1) { - setDrawableBounds(Theme.dialogs_halfCheckDrawable, halfCheckDrawLeft, checkDrawTop); - Theme.dialogs_halfCheckDrawable.draw(canvas); - setDrawableBounds(Theme.dialogs_checkReadDrawable, checkDrawLeft, checkDrawTop); - Theme.dialogs_checkReadDrawable.draw(canvas); - } else { - setDrawableBounds(Theme.dialogs_checkDrawable, checkDrawLeft, checkDrawTop); - Theme.dialogs_checkDrawable.draw(canvas); + if (printingStringType >= 0) { + StatusDrawable statusDrawable = Theme.getChatStatusDrawable(printingStringType); + if (statusDrawable != null) { + canvas.save(); + int left = LocaleController.isRTL ? messageLeft + messageLayout.getWidth() - statusDrawable.getIntrinsicWidth() : messageLeft; + if (printingStringType == 1 || printingStringType == 4) { + canvas.translate(left, messageTop + (printingStringType == 1 ? AndroidUtilities.dp(1) : 0)); + } else { + canvas.translate(left, messageTop + (AndroidUtilities.dp(18) - statusDrawable.getIntrinsicHeight()) / 2f); + } + statusDrawable.draw(canvas); + invalidate(left, messageTop, left + statusDrawable.getIntrinsicWidth(), messageTop + statusDrawable.getIntrinsicHeight()); + canvas.restore(); } } } + + if (currentDialogFolderId == 0) { + int currentStatus = (drawClock ? 1 : 0) + (drawCheck1 ? 2 : 0) + (drawCheck2 ? 4 : 0); + if (lastStatusDrawableParams >= 0 && lastStatusDrawableParams != currentStatus && !statusDrawableAnimationInProgress) { + createStatusDrawableAnimator(lastStatusDrawableParams, currentStatus); + } + if (statusDrawableAnimationInProgress) { + currentStatus = animateToStatusDrawableParams; + } + + boolean drawClock = (currentStatus & 1) != 0; + boolean drawCheck1 = (currentStatus & 2) != 0; + boolean drawCheck2 = (currentStatus & 4) != 0; + + if (statusDrawableAnimationInProgress) { + boolean outDrawClock = (animateFromStatusDrawableParams & 1) != 0; + boolean outDrawCheck1 = (animateFromStatusDrawableParams & 2) != 0; + boolean outDrawCheck2 = (animateFromStatusDrawableParams & 4) != 0; + if (!drawClock && !outDrawClock && outDrawCheck2 && !outDrawCheck1 && drawCheck1 && drawCheck2) { + drawCheckStatus(canvas, drawClock, drawCheck1, drawCheck2, true, statusDrawableProgress); + } else { + drawCheckStatus(canvas, outDrawClock, outDrawCheck1, outDrawCheck2, false, 1f - statusDrawableProgress); + drawCheckStatus(canvas, drawClock, drawCheck1, drawCheck2, false, statusDrawableProgress); + } + } else { + drawCheckStatus(canvas, drawClock, drawCheck1, drawCheck2, false,1f); + } + lastStatusDrawableParams = (this.drawClock ? 1 : 0) + (this.drawCheck1 ? 2 : 0) + (this.drawCheck2 ? 4 : 0); + } + if (dialogMuted && !drawVerified && !drawScam) { setDrawableBounds(Theme.dialogs_muteDrawable, nameMuteLeft - AndroidUtilities.dp(useForceThreeLines || SharedConfig.useThreeLinesLayout ? 0 : 1), AndroidUtilities.dp(SharedConfig.useThreeLinesLayout ? 13.5f : 17.5f)); Theme.dialogs_muteDrawable.draw(canvas); @@ -2449,6 +2599,35 @@ public class DialogCell extends BaseCell { } } + private void createStatusDrawableAnimator(int lastStatusDrawableParams, int currentStatus) { + statusDrawableProgress = 0f; + statusDrawableAnimator = ValueAnimator.ofFloat(0,1f); + statusDrawableAnimator.setDuration(220); + + statusDrawableAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animateFromStatusDrawableParams = lastStatusDrawableParams; + animateToStatusDrawableParams = currentStatus; + statusDrawableAnimator.addUpdateListener(valueAnimator -> { + statusDrawableProgress = (float) valueAnimator.getAnimatedValue(); + invalidate(); + }); + statusDrawableAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + int currentStatus = (DialogCell.this.drawClock ? 1 : 0) + (DialogCell.this.drawCheck1 ? 2 : 0) + (DialogCell.this.drawCheck2 ? 4 : 0); + if (animateToStatusDrawableParams != currentStatus) { + createStatusDrawableAnimator(animateToStatusDrawableParams, currentStatus); + } else { + statusDrawableAnimationInProgress = false; + DialogCell.this.lastStatusDrawableParams = animateToStatusDrawableParams; + } + invalidate(); + } + }); + statusDrawableAnimationInProgress = true; + statusDrawableAnimator.start(); + } + public void startOutAnimation() { if (archivedChatsDrawable != null) { archivedChatsDrawable.outCy = avatarImage.getCenterY(); 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 1ff9d296a..0152ee1a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -90,6 +90,29 @@ public class MentionCell extends LinearLayout { usernameTextView.setVisibility(VISIBLE); } + public void setChat(TLRPC.Chat chat) { + if (chat == null) { + nameTextView.setText(""); + usernameTextView.setText(""); + imageView.setImageDrawable(null); + return; + } + avatarDrawable.setInfo(chat); + if (chat.photo != null && chat.photo.photo_small != null) { + imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); + } else { + imageView.setImageDrawable(avatarDrawable); + } + nameTextView.setText(chat.title); + if (chat.username != null) { + usernameTextView.setText("@" + chat.username); + } else { + usernameTextView.setText(""); + } + imageView.setVisibility(VISIBLE); + usernameTextView.setVisibility(VISIBLE); + } + public void setText(String text) { imageView.setVisibility(INVISIBLE); usernameTextView.setVisibility(INVISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java index b979b1121..ad366d8b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java @@ -100,6 +100,7 @@ public class SendLocationCell extends FrameLayout { accurateTextView.setAlpha(value ? 1.0f : 0.5f); imageView.setAlpha(value ? 1.0f : 0.5f); } + checkText(); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java index ff4d541e8..df5757a3e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedAudioCell.java @@ -175,7 +175,7 @@ public class SharedAudioCell extends FrameLayout implements DownloadController.F CharSequence caption = Emoji.replaceEmoji(currentMessageObject.messageOwner.message.replace("\n", " ").replaceAll(" +", " ").trim(), Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); CharSequence sequence = AndroidUtilities.highlightText(caption, currentMessageObject.highlightedWords); if (sequence != null) { - sequence = TextUtils.ellipsize(AndroidUtilities.ellipsizeCenterEnd(sequence, currentMessageObject.highlightedWords.get(0), maxWidth, captionTextPaint), captionTextPaint, maxWidth, TextUtils.TruncateAt.END); + sequence = TextUtils.ellipsize(AndroidUtilities.ellipsizeCenterEnd(sequence, currentMessageObject.highlightedWords.get(0), maxWidth, captionTextPaint, 130), captionTextPaint, maxWidth, TextUtils.TruncateAt.END); captionLayout = new StaticLayout(sequence, captionTextPaint, maxWidth + AndroidUtilities.dp(4), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } 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 dd0e2d42f..365634f0c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java @@ -530,7 +530,7 @@ public class SharedDocumentCell extends FrameLayout implements DownloadControlle int h = AndroidUtilities.dp(5 + 29) + nameTextView.getMeasuredHeight() + (needDivider ? 1 : 0); if (caption != null && captionTextView != null && message.hasHighlightedWords()) { ignoreRequestLayout = true; - captionTextView.setText(AndroidUtilities.ellipsizeCenterEnd(caption, message.highlightedWords.get(0), captionTextView.getMeasuredWidth(), captionTextView.getPaint())); + captionTextView.setText(AndroidUtilities.ellipsizeCenterEnd(caption, message.highlightedWords.get(0), captionTextView.getMeasuredWidth(), captionTextView.getPaint(), 130)); ignoreRequestLayout = false; h += captionTextView.getMeasuredHeight() + AndroidUtilities.dp(3); 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 fd96f65f1..c3316ed53 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java @@ -356,7 +356,7 @@ public class SharedLinkCell extends FrameLayout { CharSequence caption = Emoji.replaceEmoji(message.messageOwner.message.replace("\n", " ").replaceAll(" +", " ").trim(), Theme.chat_msgTextPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); CharSequence sequence = AndroidUtilities.highlightText(caption, message.highlightedWords); if (sequence != null) { - sequence = TextUtils.ellipsize(AndroidUtilities.ellipsizeCenterEnd(sequence, message.highlightedWords.get(0), maxWidth, captionTextPaint), captionTextPaint, maxWidth, TextUtils.TruncateAt.END); + sequence = TextUtils.ellipsize(AndroidUtilities.ellipsizeCenterEnd(sequence, message.highlightedWords.get(0), maxWidth, captionTextPaint, 130), captionTextPaint, maxWidth, TextUtils.TruncateAt.END); captionLayout = new StaticLayout(sequence, captionTextPaint, maxWidth + AndroidUtilities.dp(4), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java index 23b47c34b..5268aba04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSelectionHelper.java @@ -1542,7 +1542,7 @@ public abstract class TextSelectionHelper 0) { + } else if (messageObject != null && messageObject.textLayoutBlocks != null && messageObject.textLayoutBlocks.size() > 0) { MessageObject.TextLayoutBlock block = messageObject.textLayoutBlocks.get(messageObject.textLayoutBlocks.size() - 1); textArea.set( maybeTextX, maybeTextY, diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeBioActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeBioActivity.java index 3f45ebe98..86dfe3852 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangeBioActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeBioActivity.java @@ -209,7 +209,7 @@ public class ChangeBioActivity extends BaseFragment { FileLog.e(e); } userFull.about = newName; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, user.id, userFull, null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.userInfoDidLoad, user.id, userFull); finishFragment(); }); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java index f39bbb23b..722fc0975 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelAdminLogActivity.java @@ -2472,13 +2472,13 @@ public class ChannelAdminLogActivity extends BaseFragment implements Notificatio themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInClockDrawable}, null, Theme.key_chat_inSentClock)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInSelectedClockDrawable}, null, Theme.key_chat_inSentClockSelected)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaCheckDrawable, Theme.chat_msgMediaHalfCheckDrawable}, null, Theme.key_chat_mediaSentCheck)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgStickerHalfCheckDrawable, Theme.chat_msgStickerCheckDrawable, Theme.chat_msgStickerClockDrawable, Theme.chat_msgStickerViewsDrawable, Theme.chat_msgStickerRepliesDrawable}, null, Theme.key_chat_serviceText)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgStickerHalfCheckDrawable, Theme.chat_msgStickerCheckDrawable, Theme.chat_msgStickerClockDrawable, Theme.chat_msgStickerViewsDrawable, Theme.chat_msgStickerRepliesDrawable, Theme.chat_msgStickerPinnedDrawable}, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaClockDrawable}, null, Theme.key_chat_mediaSentClock)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsDrawable, Theme.chat_msgOutRepliesDrawable}, null, Theme.key_chat_outViews)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsSelectedDrawable, Theme.chat_msgOutRepliesSelectedDrawable}, null, Theme.key_chat_outViewsSelected)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsDrawable, Theme.chat_msgInRepliesDrawable}, null, Theme.key_chat_inViews)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsSelectedDrawable, Theme.chat_msgInRepliesSelectedDrawable}, null, Theme.key_chat_inViewsSelected)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaViewsDrawable, Theme.chat_msgMediaRepliesDrawable}, null, Theme.key_chat_mediaViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsDrawable, Theme.chat_msgOutRepliesDrawable, Theme.chat_msgOutPinnedDrawable}, null, Theme.key_chat_outViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsSelectedDrawable, Theme.chat_msgOutRepliesSelectedDrawable, Theme.chat_msgOutPinnedSelectedDrawable}, null, Theme.key_chat_outViewsSelected)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsDrawable, Theme.chat_msgInRepliesDrawable, Theme.chat_msgInPinnedDrawable}, null, Theme.key_chat_inViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsSelectedDrawable, Theme.chat_msgInRepliesSelectedDrawable, Theme.chat_msgInPinnedSelectedDrawable}, null, Theme.key_chat_inViewsSelected)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaViewsDrawable, Theme.chat_msgMediaRepliesDrawable, Theme.chat_msgMediaPinnedDrawable}, null, Theme.key_chat_mediaViews)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutMenuDrawable}, null, Theme.key_chat_outMenu)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutMenuSelectedDrawable}, null, Theme.key_chat_outMenuSelected)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInMenuDrawable}, null, Theme.key_chat_inMenu)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java index 203a16705..2b718acc1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Charts/BaseChartView.java @@ -17,6 +17,7 @@ import android.graphics.RectF; import android.os.Build; import android.os.Bundle; import android.text.TextPaint; +import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -1465,6 +1466,7 @@ public abstract class BaseChartView legendSignatureView.setVisibility(VISIBLE); selectionA = 1f; moveLegend(chartFullWidth * (pickerDelegate.pickerStart) - HORIZONTAL_PADDING); + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); } public long getStartDate() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index f45fe4343..61a16776e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -41,6 +41,7 @@ import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; @@ -195,6 +196,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.MessageBackgroundDrawable; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PhonebookShareAlert; +import org.telegram.ui.Components.PinnedLineView; import org.telegram.ui.Components.PipRoundVideoView; import org.telegram.ui.Components.PollVotesAlert; import org.telegram.ui.Components.RLottieDrawable; @@ -226,6 +228,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.regex.Matcher; @@ -275,7 +278,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ClippingImageView animatingImageView; public RecyclerListView chatListView; private ChatListItemAnimator chatListItemAniamtor; - private int chatListViewClipTop; private GridLayoutManagerFixed chatLayoutManager; public ChatActivityAdapter chatAdapter; private UnreadCounterTextView bottomOverlayChatText; @@ -346,12 +348,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private AnimatorSet voiceHintAnimation; private View emojiButtonRed; private FrameLayout pinnedMessageView; - private View pinnedLineView; + private View blurredView; + private PinnedLineView pinnedLineView; + private boolean setPinnedTextTranslationX; private AnimatorSet pinnedMessageViewAnimator; - private BackupImageView pinnedMessageImageView; - private SimpleTextView pinnedMessageNameTextView; + private BackupImageView[] pinnedMessageImageView = new BackupImageView[2]; + private SimpleTextView[] pinnedNameTextView = new SimpleTextView[2]; + private SimpleTextView[] pinnedMessageTextView = new SimpleTextView[2]; + private NumberTextView pinnedCounterTextView; + private int pinnedCounterTextViewX; + private AnimatorSet[] pinnedNextAnimation = new AnimatorSet[2]; private ImageView closePinned; - private SimpleTextView pinnedMessageTextView; + private ImageView pinnedListButton; + private AnimatorSet pinnedListAnimator; private FrameLayout alertView; private Runnable hideAlertViewRunnable; private TextView alertNameTextView; @@ -377,8 +386,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean checkTextureViewPosition; private boolean searchingForUser; private TLRPC.User searchingUserMessages; + private TLRPC.Chat searchingChatMessages; private UndoView undoView; private UndoView topUndoView; + private Bulletin pinBulletin; + private boolean showPinBulletin; + private int pinBullerinTag; private boolean openKeyboardOnAttachMenuClose; private MessageObject hintMessageObject; @@ -388,11 +401,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private MessagesSearchAdapter messagesSearchAdapter; private AnimatorSet messagesSearchListViewAnimation; - private boolean inScheduleMode; + public static final int MODE_SCHEDULED = 1; + public static final int MODE_PINNED = 2; + + private int chatMode; private int scheduledMessagesCount = -1; private MessageObject threadMessageObject; - private boolean replyMessageVisible = true; + private boolean threadMessageVisible = true; private ArrayList threadMessageObjects; private MessageObject replyMessageHeaderObject; private int threadMessageId; @@ -432,8 +448,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int mentionListViewLastViewPosition; private boolean mentionListViewIsScrolling; - private MessageObject pinnedMessageObject; - private int loadingPinnedMessage; + private ArrayList pinnedMessageIds = new ArrayList<>(); + private HashMap pinnedMessageObjects = new HashMap<>(); + private SparseArray loadingPinnedMessages = new SparseArray<>(); + private int currentPinnedMessageId; + private int[] currentPinnedMessageIndex = new int[1]; + private int forceNextPinnedMessageId; + private boolean forceScrollToFirst; + private int loadedPinnedMessagesCount; + private int totalPinnedMessagesCount; + private boolean loadingPinnedMessagesList; + private boolean pinnedEndReached; private AnimatorSet pagedownButtonAnimation; private ObjectAnimator mentiondownButtonAnimation; @@ -506,6 +531,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int cantForwardMessagesCount; private int canForwardMessagesCount; private int canEditMessagesCount; + private int cantSaveMessagesCount; + private int canSaveMusicCount; + private int canSaveDocumentsCount; private ArrayList waitingForLoad = new ArrayList<>(); private boolean needRemovePreviousSameChatActivity = true; @@ -585,6 +613,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private Paint scrimPaint; private View scrimView; + private int popupAnimationIndex = -1; private AnimatorSet scrimAnimatorSet; private ActionBarPopupWindow scrimPopupWindow; private ActionBarMenuSubItem[] scrimPopupWindowItems; @@ -592,6 +621,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ChatActivityDelegate chatActivityDelegate; private RecyclerAnimationScrollHelper chatScrollHelper; + private int postponedScrollMinMessageId; private int postponedScrollToLastMessageQueryIndex; private int postponedScrollMessageId; private boolean postponedScrollIsCanceled; @@ -619,6 +649,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int distanceToPeer; private int chatListViewPaddingTop; + private int contentPaddingTop; private float contentPanTranslation; private float floatingDateViewOffset; @@ -637,7 +668,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.commentsRead, NotificationCenter.messagesReadEncrypted, NotificationCenter.messagesReadContent, - NotificationCenter.pinnedMessageDidLoad, + NotificationCenter.commentsRead, + NotificationCenter.didLoadPinnedMessages, NotificationCenter.newDraftReceived, NotificationCenter.updateMentionsCount, NotificationCenter.didUpdateConnectionState, @@ -646,6 +678,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.contactsDidLoad, NotificationCenter.chatInfoCantLoad, NotificationCenter.userInfoDidLoad, + NotificationCenter.pinnedInfoDidLoad, NotificationCenter.didSetNewWallpapper, NotificationCenter.didApplyNewTheme }; @@ -663,11 +696,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; private int chatEmojiViewPadding; + private int fixedKeyboardHeight = -1; + private boolean invalidateMessagesVisiblePart; + + public int getChatListViewPadding() { + return chatListViewPaddingTop; + } private interface ChatActivityDelegate { void openReplyMessage(int mid); void openSearch(String text); + + default void onUnpin(boolean all, boolean hide) { + + } } private class UnreadCounterTextView extends View { @@ -941,10 +984,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatActionCell && currentChat != null) { object.dialogId = -currentChat.id; } - if (pinnedMessageView != null && pinnedMessageView.getTag() == null || topChatPanelView != null && topChatPanelView.getTag() == null) { - object.clipTopAddition = AndroidUtilities.dp(48); - } - object.clipTopAddition += chatListViewClipTop; + object.clipTopAddition = chatListViewPaddingTop - AndroidUtilities.dp(4); return object; } } @@ -1013,9 +1053,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int star = 22; private final static int edit = 23; private final static int add_shortcut = 24; - private final static int show_pinned = 25; + private final static int save_to = 25; + private final static int translate = 101; - private final static int share_key = 28; + private final static int show_pinned = 102; + private final static int share_key = 103; private final static int bot_help = 30; private final static int bot_settings = 31; @@ -1122,7 +1164,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final int chatId = arguments.getInt("chat_id", 0); final int userId = arguments.getInt("user_id", 0); final int encId = arguments.getInt("enc_id", 0); - inScheduleMode = arguments.getBoolean("scheduled", false); + chatMode = arguments.getInt("chatMode", 0); inlineReturn = arguments.getLong("inline_return", 0); String inlineQuery = arguments.getString("inline_query"); startLoadFromMessageId = arguments.getInt("message_id", 0); @@ -1235,7 +1277,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addPostponeNotificationsCallback(postponeNotificationsWhileLoadingCallback); - if (!inScheduleMode) { + if (chatMode != MODE_SCHEDULED) { if (threadMessageId == 0) { getNotificationCenter().addObserver(this, NotificationCenter.screenshotTook); getNotificationCenter().addObserver(this, NotificationCenter.encryptedChatUpdated); @@ -1245,7 +1287,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.newDraftReceived); getNotificationCenter().addObserver(this, NotificationCenter.chatOnlineCountDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.peerSettingsDidLoad); - getNotificationCenter().addObserver(this, NotificationCenter.pinnedMessageDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.didLoadPinnedMessages); getNotificationCenter().addObserver(this, NotificationCenter.commentsRead); getNotificationCenter().addObserver(this, NotificationCenter.changeRepliesCounter); getNotificationCenter().addObserver(this, NotificationCenter.messagesRead); @@ -1266,7 +1308,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.didUpdateConnectionState); getNotificationCenter().addObserver(this, NotificationCenter.updateInterfaces); - getNotificationCenter().addObserver(this, NotificationCenter.didReceiveNewMessages); + if (chatMode != MODE_PINNED) { + getNotificationCenter().addObserver(this, NotificationCenter.didReceiveNewMessages); + } getNotificationCenter().addObserver(this, NotificationCenter.closeChats); getNotificationCenter().addObserver(this, NotificationCenter.messagesDeleted); getNotificationCenter().addObserver(this, NotificationCenter.historyCleared); @@ -1292,6 +1336,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().addObserver(this, NotificationCenter.botInfoDidLoad); getNotificationCenter().addObserver(this, NotificationCenter.chatInfoCantLoad); getNotificationCenter().addObserver(this, NotificationCenter.userInfoDidLoad); + getNotificationCenter().addObserver(this, NotificationCenter.pinnedInfoDidLoad); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didSetNewWallpapper); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.didApplyNewTheme); NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.goingToPreviewTheme); @@ -1304,30 +1349,50 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not super.onFragmentCreate(); - loading = true; + if (chatMode == MODE_PINNED) { + ArrayList messageObjects = new ArrayList<>(); + for (int a = 0, N = pinnedMessageIds.size(); a < N; a++) { + Integer id = pinnedMessageIds.get(a); + MessageObject object = pinnedMessageObjects.get(id); + if (object != null) { + MessageObject o = new MessageObject(object.currentAccount, object.messageOwner, true, false); + o.replyMessageObject = object.replyMessageObject; + o.mediaExists = object.mediaExists; + o.attachPathExists = object.attachPathExists; + messageObjects.add(o); + } + } + int loadIndex = lastLoadIndex++; + waitingForLoad.add(loadIndex); + getNotificationCenter().postNotificationName(NotificationCenter.messagesDidLoad, dialog_id, messageObjects.size(), messageObjects, false, 0, last_message_id, 0, 0, 2, true, classGuid, loadIndex, pinnedMessageIds.get(0), 0, MODE_PINNED); + } else { + loading = true; + } if (isThreadChat()) { if (highlightMessageId == startLoadFromMessageId) { needSelectFromMessageId = true; } - } else if (!inScheduleMode) { - if (currentEncryptedChat == null) { - getMediaDataController().loadBotKeyboard(dialog_id); - } - getMessagesController().loadPeerSettings(currentUser, currentChat); - getMessagesController().setLastCreatedDialogId(dialog_id, inScheduleMode, true); - - if (startLoadFromMessageId == 0) { - SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); - int messageId = sharedPreferences.getInt("diditem" + dialog_id, 0); - if (messageId != 0) { - wasManualScroll = true; - loadingFromOldPosition = true; - startLoadFromMessageOffset = sharedPreferences.getInt("diditemo" + dialog_id, 0); - startLoadFromMessageId = messageId; + } else { + getMessagesController().setLastCreatedDialogId(dialog_id, chatMode == MODE_SCHEDULED, true); + if (chatMode == 0) { + if (currentEncryptedChat == null) { + getMediaDataController().loadBotKeyboard(dialog_id); + } + getMessagesController().loadPeerSettings(currentUser, currentChat); + + if (startLoadFromMessageId == 0) { + SharedPreferences sharedPreferences = MessagesController.getNotificationsSettings(currentAccount); + int messageId = sharedPreferences.getInt("diditem" + dialog_id, 0); + if (messageId != 0) { + wasManualScroll = true; + loadingFromOldPosition = true; + startLoadFromMessageOffset = sharedPreferences.getInt("diditemo" + dialog_id, 0); + startLoadFromMessageId = messageId; + } + } else { + showScrollToMessageError = true; + needSelectFromMessageId = true; } - } else { - showScrollToMessageError = true; - needSelectFromMessageId = true; } } @@ -1337,39 +1402,45 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat.megagroup && !getMessagesController().isChannelAdminsLoaded(currentChat.id)) { getMessagesController().loadChannelAdmins(currentChat.id, true); } - getMessagesStorage().loadChatInfo(currentChat.id, null, true, false); - if (!inScheduleMode && chatInfo != null && ChatObject.isChannel(currentChat) && chatInfo.migrated_from_chat_id != 0 && !isThreadChat()) { + if (chatMode != MODE_PINNED) { + getMessagesStorage().loadChatInfo(currentChat.id, ChatObject.isChannel(currentChat), null, true, false, startLoadFromMessageId); + } + if (chatMode == 0 && chatInfo != null && ChatObject.isChannel(currentChat) && chatInfo.migrated_from_chat_id != 0 && !isThreadChat()) { mergeDialogId = -chatInfo.migrated_from_chat_id; maxMessageId[1] = chatInfo.migrated_from_max_id; } loadInfo = chatInfo == null; } else if (currentUser != null) { - getMessagesController().loadUserInfo(currentUser, true, classGuid); + if (chatMode != MODE_PINNED) { + getMessagesController().loadUserInfo(currentUser, true, classGuid, startLoadFromMessageId); + } loadInfo = userInfo == null; } - waitingForLoad.add(lastLoadIndex); - if (startLoadFromMessageId != 0 && (!isThreadChat() || startLoadFromMessageId == highlightMessageId)) { - startLoadFromMessageIdSaved = startLoadFromMessageId; - if (migrated_to != 0) { - mergeDialogId = migrated_to; - getMessagesController().loadMessages(mergeDialogId, 0, loadInfo, loadingFromOldPosition ? 50 : (AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20), startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + if (chatMode != MODE_PINNED) { + waitingForLoad.add(lastLoadIndex); + if (startLoadFromMessageId != 0 && (!isThreadChat() || startLoadFromMessageId == highlightMessageId)) { + startLoadFromMessageIdSaved = startLoadFromMessageId; + if (migrated_to != 0) { + mergeDialogId = migrated_to; + getMessagesController().loadMessages(mergeDialogId, 0, loadInfo, loadingFromOldPosition ? 50 : (AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20), startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + } else { + getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, loadingFromOldPosition ? 50 : (AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20), startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + } } else { - getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, loadingFromOldPosition ? 50 : (AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20), startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); - } - } else { - if (historyPreloaded) { - lastLoadIndex++; - } else { - getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + if (historyPreloaded) { + lastLoadIndex++; + } else { + getMessagesController().loadMessages(dialog_id, mergeDialogId, loadInfo, AndroidUtilities.isTablet() || isThreadChat() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + } } } - if (!inScheduleMode && !isThreadChat()) { + if (chatMode == 0 && !isThreadChat()) { waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 1, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), true, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 1, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), MODE_SCHEDULED, threadMessageId, replyMaxReadId, lastLoadIndex++); } - if (!inScheduleMode) { + if (chatMode == 0) { if (userId != 0 && currentUser.bot) { getMediaDataController().loadBotInfo(userId, true, classGuid); } else if (chatInfo instanceof TLRPC.TL_chatFull) { @@ -1427,6 +1498,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } + private void hideUndoViews() { + if (undoView != null) { + undoView.hide(true, 0); + } + if (pinBulletin != null) { + pinBulletin.hide(false); + } + if (topUndoView != null) { + topUndoView.hide(true, 0); + } + } + @Override public void onFragmentDestroy() { super.onFragmentDestroy(); @@ -1442,18 +1525,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatAttachAlert != null) { chatAttachAlert.dismissInternal(); } - if (undoView != null) { - undoView.hide(true, 0); - } - if (topUndoView != null) { - topUndoView.hide(true, 0); - } + hideUndoViews(); if (chatInviteRunnable != null) { AndroidUtilities.cancelRunOnUIThread(chatInviteRunnable); chatInviteRunnable = null; } getNotificationCenter().removePostponeNotificationsCallback(postponeNotificationsWhileLoadingCallback); - getMessagesController().setLastCreatedDialogId(dialog_id, inScheduleMode, false); + getMessagesController().setLastCreatedDialogId(dialog_id, chatMode == MODE_SCHEDULED, false); getNotificationCenter().removeObserver(this, NotificationCenter.messagesDidLoad); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.didUpdateConnectionState); @@ -1496,10 +1574,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.messagePlayingPlayStateChanged); getNotificationCenter().removeObserver(this, NotificationCenter.didUpdateMessagesViews); getNotificationCenter().removeObserver(this, NotificationCenter.chatInfoCantLoad); - getNotificationCenter().removeObserver(this, NotificationCenter.pinnedMessageDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.didLoadPinnedMessages); getNotificationCenter().removeObserver(this, NotificationCenter.peerSettingsDidLoad); getNotificationCenter().removeObserver(this, NotificationCenter.newDraftReceived); getNotificationCenter().removeObserver(this, NotificationCenter.userInfoDidLoad); + getNotificationCenter().removeObserver(this, NotificationCenter.pinnedInfoDidLoad); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didSetNewWallpapper); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.didApplyNewTheme); NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.goingToPreviewTheme); @@ -1516,7 +1595,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().removeObserver(this, NotificationCenter.didVerifyMessagesStickers); } - if (!inScheduleMode && AndroidUtilities.isTablet()) { + if (chatMode == 0 && AndroidUtilities.isTablet()) { getNotificationCenter().postNotificationName(NotificationCenter.openedChatChanged, dialog_id, true); } if (currentUser != null) { @@ -1600,12 +1679,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCanCopyIds[a].clear(); selectedMessagesCanStarIds[a].clear(); } + scheduledOrNoSoundHint = null; + distanseTopView = null; + aspectRatioFrameLayout = null; + videoTextureView = null; + searchAsListHint = null; + mediaBanTooltip = null; + noSoundHintView = null; + forwardHintView = null; + textSelectionHint = null; + emojiButtonRed = null; + gifHintTextView = null; + pollHintView = null; + videoPlayerContainer = null; + voiceHintTextView = null; + blurredView = null; + dummyMessageCell = null; cantDeleteMessagesCount = 0; canEditMessagesCount = 0; cantForwardMessagesCount = 0; canForwardMessagesCount = 0; - videoPlayerContainer = null; - voiceHintTextView = null; + cantSaveMessagesCount = 0; + canSaveMusicCount = 0; + canSaveDocumentsCount = 0; hasOwnBackground = true; if (chatAttachAlert != null) { @@ -1681,6 +1777,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (id == forward || id == forward_noquote) { noForwardQuote = id == forward_noquote; openForward(); + } else if (id == save_to) { + ArrayList messageObjects = new ArrayList<>(); + for (int a = 1; a >= 0; a--) { + for (int b = 0; b < selectedMessagesIds[a].size(); b++) { + messageObjects.add(selectedMessagesIds[a].valueAt(b)); + } + selectedMessagesIds[a].clear(); + selectedMessagesCanCopyIds[a].clear(); + selectedMessagesCanStarIds[a].clear(); + } + boolean isMusic = canSaveMusicCount > 0; + hideActionMode(); + updatePinnedMessageView(true); + updateVisibleRows(); + MediaController.saveFilesFromMessages(getParentActivity(), getAccountInstance(), messageObjects, (count) -> { + if (count > 0) { + if (getParentActivity() == null) { + return; + } + BulletinFactory.of(ChatActivity.this).createDownloadBulletin(isMusic ? BulletinFactory.FileType.AUDIOS : BulletinFactory.FileType.UNKNOWNS, count).show(); + } + }); } else if (id == chat_enc_timer) { if (getParentActivity() == null) { return; @@ -1747,14 +1865,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getNotificationCenter().postNotificationName(NotificationCenter.needDeleteDialog, dialog_id, currentUser, currentChat, param); } else { clearingHistory = true; - undoView.showWithAction(dialog_id, id == clear_history ? UndoView.ACTION_CLEAR : UndoView.ACTION_DELETE, () -> { - if (chatInfo != null && chatInfo.pinned_msg_id != 0) { + undoView.showWithAction(dialog_id, UndoView.ACTION_CLEAR, () -> { + if (!pinnedMessageIds.isEmpty()) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("pin_" + dialog_id, chatInfo.pinned_msg_id).apply(); - updatePinnedMessageView(true); - } else if (userInfo != null && userInfo.pinned_msg_id != 0) { - SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - preferences.edit().putInt("pin_" + dialog_id, userInfo.pinned_msg_id).apply(); + preferences.edit().putInt("pin_" + dialog_id, pinnedMessageIds.get(0)).commit(); + pinnedMessageIds.clear(); + pinnedMessageObjects.clear(); + currentPinnedMessageId = 0; + loadedPinnedMessagesCount = 0; + totalPinnedMessagesCount = 0; updatePinnedMessageView(true); } getMessagesController().deleteDialog(dialog_id, 1, param); @@ -1906,11 +2025,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (inPreviewMode || inBubbleMode) { avatarContainer.setOccupyStatusBar(false); } - actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : (chatMode == MODE_PINNED ? 10 : 0), 0, 40, 0)); ActionBarMenu menu = actionBar.createMenu(); - if (currentEncryptedChat == null && !inScheduleMode) { + if (currentEncryptedChat == null && chatMode == 0) { searchItem = menu.addItem(0, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { boolean searchWas; @@ -1937,6 +2056,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionLayoutManager.setReverseLayout(false); mentionsAdapter.setSearchingMentions(false); searchingUserMessages = null; + searchingChatMessages = null; searchItem.setSearchFieldHint(LocaleController.getString("Search", R.string.Search)); searchItem.setSearchFieldCaption(null); avatarContainer.setVisibility(View.VISIBLE); @@ -2005,7 +2125,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void onSearchPressed(EditText editText) { searchWas = true; updateSearchButtons(0, 0, -1); - getMediaDataController().searchMessagesInChat(editText.getText().toString(), dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages); + getMediaDataController().searchMessagesInChat(editText.getText().toString(), dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); } @Override @@ -2013,14 +2133,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showMessagesSearchListView(false); if (searchingForUser) { mentionsAdapter.searchUsernameOrHashtag("@" + editText.getText().toString(), 0, messages, true); - } else if (!searchingForUser && searchingUserMessages == null && searchUserButton != null && TextUtils.equals(editText.getText(), LocaleController.getString("SearchFrom", R.string.SearchFrom))) { + } else if (searchingUserMessages == null && searchingChatMessages == null && searchUserButton != null && TextUtils.equals(editText.getText(), LocaleController.getString("SearchFrom", R.string.SearchFrom))) { searchUserButton.callOnClick(); } } @Override public void onCaptionCleared() { - if (searchingUserMessages != null) { + if (searchingUserMessages != null || searchingChatMessages != null) { searchUserButton.callOnClick(); } else { if (searchingForUser) { @@ -2032,6 +2152,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchCalendarButton.setVisibility(View.VISIBLE); searchUserButton.setVisibility(View.VISIBLE); searchingUserMessages = null; + searchingChatMessages = null; } } @@ -2047,7 +2168,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchItemVisible = false; } - if (!inScheduleMode && threadMessageId == 0 && !UserObject.isReplyUser(currentUser)) { + if (chatMode == 0 && threadMessageId == 0 && !UserObject.isReplyUser(currentUser)) { headerItem = menu.addItem(0, R.drawable.ic_ab_other); headerItem.setContentDescription(LocaleController.getString("AccDescrMoreOptions", R.string.AccDescrMoreOptions)); if (currentUser != null) { @@ -2084,7 +2205,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stringBuilder = new SpannableStringBuilder(LocaleController.getString("Mono", R.string.Mono)); stringBuilder.setSpan(new TypefaceSpan(Typeface.MONOSPACE), 0, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); editTextItem.addSubItem(text_mono, stringBuilder); - if (currentEncryptedChat == null || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { + if (currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101) { stringBuilder = new SpannableStringBuilder(LocaleController.getString("Strike", R.string.Strike)); TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(); run.flags |= TextStyleSpan.FLAG_STYLE_STRIKE; @@ -2139,7 +2260,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentEncryptedChat != null) { timeItem2 = headerItem.addSubItem(chat_enc_timer, R.drawable.msg_timer, LocaleController.getString("SetTimer", R.string.SetTimer)); } - if (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup && TextUtils.isEmpty(currentChat.username)) { + if (!ChatObject.isChannel(currentChat) || currentChat.megagroup && TextUtils.isEmpty(currentChat.username)) { headerItem.addSubItem(clear_history, R.drawable.baseline_delete_sweep_24, LocaleController.getString("ClearHistory", R.string.ClearHistory)); } if (currentUser == null || !currentUser.self) { @@ -2178,7 +2299,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not avatarContainer.updateSubtitle(); updateTitleIcons(); - if (!inScheduleMode && !isThreadChat()) { + if (chatMode == 0 && !isThreadChat()) { attachItem = menu.addItem(chat_menu_attach, R.drawable.ic_ab_other).setOverrideMenuClick(true).setAllowCloseAnimation(false); attachItem.setVisibility(View.GONE); } @@ -2208,6 +2329,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionModeViews.add(actionMode.addItemWithWidth(copy, R.drawable.baseline_content_copy_24, AndroidUtilities.dp(54), LocaleController.getString("Copy", R.string.Copy))); if (currentEncryptedChat == null) { + actionModeViews.add(actionMode.addItemWithWidth(save_to, R.drawable.msg_download, AndroidUtilities.dp(54), LocaleController.getString("SaveToMusic", R.string.SaveToMusic))); actionModeViews.add(actionMode.addItemWithWidth(forward, R.drawable.msg_forward, AndroidUtilities.dp(54), LocaleController.getString("Forward", R.string.Forward))); actionModeViews.add(actionMode.addItemWithWidth(forward_noquote, R.drawable.msg_forward_noquote, AndroidUtilities.dp(54), LocaleController.getString("NoQuoteForward", R.string.NoQuoteForward))); } @@ -2249,6 +2371,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected void onTransitionStart(boolean keyboardVisible) { + wasManualScroll = true; if (chatActivityEnterView != null) { chatActivityEnterView.onAdjustPanTransitionStart(keyboardVisible); } @@ -2265,12 +2388,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { actionBar.setTranslationY(y); emptyViewContainer.setTranslationY(y / 2); + progressView.setTranslationY(y / 2); contentView.setBackgroundTranslation((int) y); instantCameraView.onPanTranslationUpdate(y); setFragmentPanTranslationOffset((int) y); invalidateChatListViewTopPadding(); + invalidateMessagesVisiblePart(); } - updateChatListViewTopPadding(); chatListView.setItemAnimator(null); chatListView.invalidate(); } @@ -2278,7 +2402,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected boolean heightAnimationEnabled() { ActionBarLayout actionBarLayout = getParentLayout(); - if (inPreviewMode || inBubbleMode || AndroidUtilities.isInMultiwindow || actionBarLayout == null) { + if (inPreviewMode || inBubbleMode || AndroidUtilities.isInMultiwindow || actionBarLayout == null || fixedKeyboardHeight > 0) { return false; } if (System.currentTimeMillis() - activityResumeTime < 250) { @@ -2325,7 +2449,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public boolean dispatchTouchEvent(MotionEvent ev) { float expandY; if (AndroidUtilities.isInMultiwindow || isInBubbleMode()) { - expandY = chatActivityEnterView != null && chatActivityEnterView.getEmojiView() != null ? chatActivityEnterView.getEmojiView().getY() : chatActivityEnterView.getY(); + expandY = chatActivityEnterView.getEmojiView() != null ? chatActivityEnterView.getEmojiView().getY() : chatActivityEnterView.getY(); } else { expandY = chatActivityEnterView.getY(); } @@ -2429,7 +2553,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { drawLaterRoundProgressCell.drawOverlays(canvas); if (drawLaterRoundProgressCell.needDrawTime()) { - drawLaterRoundProgressCell.drawTime(canvas, drawLaterRoundProgressCell.getAlpha()); + drawLaterRoundProgressCell.drawTime(canvas, drawLaterRoundProgressCell.getAlpha(), true); } } canvas.restore(); @@ -2454,19 +2578,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not float alpha = cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f; canvas.clipRect(chatListView.getLeft(), listTop, chatListView.getRight(), chatListView.getY() + chatListView.getMeasuredHeight()); canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); if (type == 0) { - cell.drawTime(canvas, alpha); + cell.drawTime(canvas, alpha, true); } else if (type == 1) { cell.drawNamesLayout(canvas, alpha); } else { cell.drawCaptionLayout(canvas, (cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_LEFT) == 0, alpha); } + cell.setInvalidatesParent(false); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { + chatActivityEnterView.checkAnimation(); updateChatListViewTopPadding(); + if (invalidateMessagesVisiblePart || (chatListItemAniamtor != null && chatListItemAniamtor.isRunning())) { + invalidateMessagesVisiblePart = false; + updateMessagesVisiblePart(false); + } super.dispatchDraw(canvas); if (chatActivityEnterView != null) { if (chatActivityEnterView.pannelAniamationInProgress() && chatActivityEnterView.getEmojiPadding() < bottomPanelTranslationY) { @@ -2484,12 +2615,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (scrimView != null) { canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), scrimPaint); - int chatListViewTop = (int) chatListView.getY(); - int chatListViewBottom = chatListViewTop + chatListView.getMeasuredHeight(); - float listTop = chatListView.getTop() + chatListView.getPaddingTop() - AndroidUtilities.dp(4); - if (threadMessageId != 0 && !replyMessageVisible) { - listTop += AndroidUtilities.dp(48); - } + float listTop = chatListView.getY() + chatListViewPaddingTop - AndroidUtilities.dp(4); MessageObject.GroupedMessages scrimGroup; if (scrimView instanceof ChatMessageCell) { scrimGroup = ((ChatMessageCell) scrimView).getCurrentMessagesGroup(); @@ -2518,54 +2644,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not continue; } - if (!groupedBackgroundWasDraw && cell != null && scrimGroup != null) { - float x = cell.getNonAnimationTranslationX(true); + if (!groupedBackgroundWasDraw && cell != null && scrimGroup != null && scrimGroup.transitionParams.cell != null) { + float x = scrimGroup.transitionParams.cell.getNonAnimationTranslationX(true); + float l = (scrimGroup.transitionParams.left + x + scrimGroup.transitionParams.offsetLeft); - float t = (scrimGroup.transitionParams.top + scrimGroup.transitionParams.offsetTop + chatListView.getY()); + float t = (scrimGroup.transitionParams.top + scrimGroup.transitionParams.offsetTop); float r = (scrimGroup.transitionParams.right + x + scrimGroup.transitionParams.offsetRight); - float b = (scrimGroup.transitionParams.bottom + scrimGroup.transitionParams.offsetBottom + chatListView.getY()); + float b = (scrimGroup.transitionParams.bottom + scrimGroup.transitionParams.offsetBottom); if (!scrimGroup.transitionParams.backgroundChangeBounds) { - t += cell.getTranslationY(); - b += cell.getTranslationY(); + t += scrimGroup.transitionParams.cell.getTranslationY(); + b += scrimGroup.transitionParams.cell.getTranslationY(); } + + if (t < chatListViewPaddingTop - AndroidUtilities.dp(20)) { + t = chatListViewPaddingTop - AndroidUtilities.dp(20); + } + + if (b > chatListView.getMeasuredHeight() + AndroidUtilities.dp(20)) { + b = chatListView.getMeasuredHeight() + AndroidUtilities.dp(20); + } + canvas.save(); canvas.clipRect(0, listTop, getMeasuredWidth(), chatListView.getY() + chatListView.getHeight()); - cell.drawBackground(canvas, (int) l, (int) t, (int) r, (int) b, scrimGroup.transitionParams.pinnedTop, scrimGroup.transitionParams.pinnedBotton); + canvas.translate(0, chatListView.getY()); + scrimGroup.transitionParams.cell.drawBackground(canvas, (int) l, (int) t, (int) r, (int) b, scrimGroup.transitionParams.pinnedTop, scrimGroup.transitionParams.pinnedBotton); canvas.restore(); groupedBackgroundWasDraw = true; } - int clipLeft = 0; - int clipBottom = 0; - - float viewClipLeft; - float viewClipRight; - float viewClipTop; - float viewClipBottom; - - if (clipLeft != 0) { - float x = chatListView.getLeft() + clipLeft + child.getTranslationX(); - float y = chatListView.getTop() + child.getTop(); - - viewClipLeft = Math.max(chatListView.getLeft(), x); - viewClipTop = Math.max(listTop, y); - viewClipRight = Math.min(chatListView.getRight(), x + child.getMeasuredWidth()); - viewClipBottom = Math.min(chatListView.getY() + chatListView.getMeasuredHeight(), chatListView.getY() + child.getTop() + child.getMeasuredHeight()); - } else if (clipBottom != 0) { - float x = chatListView.getLeft() + child.getTranslationX(); - float y = chatListView.getTop() + child.getTop(); - - viewClipLeft = Math.max(chatListView.getLeft(), x); - viewClipTop = Math.max(listTop, y); - viewClipRight = Math.min(chatListView.getRight(), x + child.getMeasuredWidth()); - viewClipBottom = Math.min(chatListView.getY() + chatListView.getMeasuredHeight(), chatListView.getY() + clipBottom); - } else { - viewClipLeft = Math.max(chatListView.getLeft(), chatListView.getLeft() + child.getX()); - viewClipTop = Math.max(listTop, chatListView.getTop() + child.getY()); - viewClipRight = Math.min(chatListView.getRight(), chatListView.getLeft() + child.getX() + child.getMeasuredWidth()); - viewClipBottom = Math.min(chatListView.getY() + chatListView.getMeasuredHeight(), chatListView.getY() + child.getY() + child.getMeasuredHeight()); - } + float viewClipLeft = Math.max(chatListView.getLeft(), chatListView.getLeft() + child.getX()); + float viewClipTop = Math.max(listTop, chatListView.getTop() + child.getY()); + float viewClipRight = Math.min(chatListView.getRight(), chatListView.getLeft() + child.getX() + child.getMeasuredWidth()); + float viewClipBottom = Math.min(chatListView.getY() + chatListView.getMeasuredHeight(), chatListView.getY() + child.getY() + child.getMeasuredHeight()); if (viewClipTop < viewClipBottom) { if (child.getAlpha() != 1f) { @@ -2573,22 +2684,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { canvas.save(); } + if (cell != null) { + cell.setInvalidatesParent(true); + } canvas.clipRect(viewClipLeft, viewClipTop, viewClipRight, viewClipBottom); canvas.translate(chatListView.getLeft() + child.getX(), chatListView.getY() + child.getY()); child.draw(canvas); canvas.restore(); + + if (cell != null) { + cell.setInvalidatesParent(false); + } } - if (position != null) { - if (position.last || position.minX == 0 && position.minY == 0) { - if (position.last) { + if (position != null || cell != null && cell.getTransitionParams().animateBackgroundBoundsInner) { + if (position == null || position.last || position.minX == 0 && position.minY == 0) { + if (position == null || position.last) { drawTimeAfter.add(cell); } - if (position.minX == 0 && position.minY == 0 && cell.hasNameLayout()) { + if (position == null || (position.minX == 0 && position.minY == 0 && cell.hasNameLayout())) { drawNamesAfter.add(cell); } } - if ((cell.hasCaptionLayout() || cell.hasCommentLayout()) && (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + if ((cell.hasCaptionLayout() || cell.hasCommentLayout()) && (position == null || (position.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0)) { drawCaptionAfter.add(cell); } } @@ -2633,6 +2751,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not super.drawChild(canvas, fireworksOverlay, SystemClock.uptimeMillis()); } } + if (fixedKeyboardHeight > 0 && keyboardHeight < AndroidUtilities.dp(20)) { + int color = Theme.getColor(Theme.key_windowBackgroundWhite); + if (backgroundPaint == null) { + backgroundPaint = new Paint(); + } + if (backgroundColor != color) { + backgroundPaint.setColor(backgroundColor = color); + } + canvas.drawRect(0,getMeasuredHeight() - fixedKeyboardHeight, getMeasuredWidth(), getMeasuredHeight(), backgroundPaint); + } } @Override @@ -2644,10 +2772,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not setMeasuredDimension(widthSize, heightSize); heightSize -= getPaddingTop(); -// if (SharedConfig.smoothKeyboard && chatActivityEnterView.isPopupShowing()) { -// setNonNoveTranslation(0); -// } - measureChildWithMargins(actionBar, widthMeasureSpec, 0, heightMeasureSpec, 0); int actionBarHeight = actionBar.getMeasuredHeight(); if (actionBar.getVisibility() == VISIBLE) { @@ -2658,19 +2782,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not measureKeyboardHeight(); } int keyboardSize = getKeyboardHeight(); - - if (keyboardSize <= AndroidUtilities.dp(20)) { - if (!inBubbleMode && !AndroidUtilities.isInMultiwindow && !SharedConfig.smoothKeyboard) { - heightSize -= chatActivityEnterView.getEmojiPadding(); - allHeight -= chatActivityEnterView.getEmojiPadding(); - chatEmojiViewPadding = 0; - } else { - chatEmojiViewPadding = chatActivityEnterView.isPopupShowing() ? chatActivityEnterView.getEmojiPadding() : 0; - } + if (fixedKeyboardHeight > 0 && keyboardSize <= AndroidUtilities.dp(20)) { + chatEmojiViewPadding = fixedKeyboardHeight; } else { - chatEmojiViewPadding = 0; + if (keyboardSize <= AndroidUtilities.dp(20)) { + chatEmojiViewPadding = chatActivityEnterView.isPopupShowing() ? chatActivityEnterView.getEmojiPadding() : 0; + } else { + chatEmojiViewPadding = 0; + } } - invalidateChatListViewTopPadding(); int childCount = getChildCount(); @@ -2689,8 +2809,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (child == null || child.getVisibility() == GONE || child == chatActivityEnterView || child == actionBar) { continue; } - if (child == chatListView) { - chatListViewClipTop = inPreviewMode ? 0 : (inputFieldHeight - AndroidUtilities.dp(51)); + if (child == blurredView) { + int contentWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); + int contentHeightSpec = MeasureSpec.makeMeasureSpec(allHeight, MeasureSpec.EXACTLY); + child.measure(contentWidthSpec, contentHeightSpec); + } else if (child == chatListView) { int contentWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); int h = heightSize - listViewTopHeight - (inPreviewMode && Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); if (keyboardSize > AndroidUtilities.dp(20) && getLayoutParams().height < 0) { @@ -2781,7 +2904,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (fixPaddingsInLayout) { globalIgnoreLayout = true; - checkListViewPaddingsInternal(); + invalidateChatListViewTopPadding(); fixPaddingsInLayout = false; chatListView.measure(MeasureSpec.makeMeasureSpec(chatListView.getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(chatListView.getMeasuredHeight(), MeasureSpec.EXACTLY)); globalIgnoreLayout = false; @@ -2805,7 +2928,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); int keyboardSize = getKeyboardHeight(); - int paddingBottom = keyboardSize <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !inBubbleMode ? chatActivityEnterView.getEmojiPadding() : 0; + int paddingBottom; + if (fixedKeyboardHeight > 0 && keyboardSize <= AndroidUtilities.dp(20)) { + paddingBottom = fixedKeyboardHeight; + } else { + paddingBottom = keyboardSize <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !inBubbleMode ? chatActivityEnterView.getEmojiPadding() : 0; + } if (!SharedConfig.smoothKeyboard) { setBottomClip(paddingBottom); } @@ -2863,7 +2991,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not childTop = lp.topMargin; } - if (child instanceof HintView) { + if (child == blurredView) { + childTop = 0; + } else if (child instanceof HintView) { childTop = 0; } else if (child == mentionContainer) { childTop -= chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(2); @@ -2889,9 +3019,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!inPreviewMode) { childTop -= (inputFieldHeight - AndroidUtilities.dp(51)); } - if (SharedConfig.smoothKeyboard) { - childTop -= paddingBottom; - } + + childTop -= paddingBottom; + if (keyboardSize > AndroidUtilities.dp(20) && getLayoutParams().height < 0) { childTop -= keyboardSize; } @@ -2906,18 +3036,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not childTop -= getPaddingTop(); } else if (child == videoPlayerContainer) { childTop = actionBar.getMeasuredHeight(); - if (SharedConfig.smoothKeyboard) { - childTop -= paddingBottom; - } + childTop -= paddingBottom; if (keyboardSize > AndroidUtilities.dp(20) && getLayoutParams().height < 0) { childTop -= keyboardSize; } } else if (child == instantCameraView || child == overlayView || child == animatingImageView) { childTop = 0; } else if (child == textSelectionHelper.getOverlayView(context)) { - if (SharedConfig.smoothKeyboard) { - childTop -= paddingBottom; - } + childTop -= paddingBottom; if (keyboardSize > AndroidUtilities.dp(20) && getLayoutParams().height < 0) { childTop -= keyboardSize; } @@ -2925,7 +3051,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not child.layout(childLeft, childTop, childLeft + width, childTop + height); } - updateMessagesVisiblePart(true); + invalidateChatListViewTopPadding(); + invalidateMessagesVisiblePart(); updateTextureViewPosition(false); if (!scrollingChatListView) { @@ -2938,6 +3065,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.setTranslationY(y); actionBar.setTranslationY(0); emptyViewContainer.setTranslationY(0); + progressView.setTranslationY(0); contentPanTranslation = 0; contentView.setBackgroundTranslation(0); instantCameraView.onPanTranslationUpdate(0); @@ -2973,7 +3101,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); emptyViewContainer.addView(greetingsViewContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 68, 0, 68, 0)); } else if (currentEncryptedChat == null) { - if (!isThreadChat() && !inScheduleMode && (currentUser != null && currentUser.self || currentChat != null && currentChat.creator)) { + if (!isThreadChat() && chatMode == 0 && (currentUser != null && currentUser.self || currentChat != null && currentChat.creator)) { bigEmptyView = new ChatBigEmptyView(context, currentChat != null ? ChatBigEmptyView.EMPTY_VIEW_TYPE_GROUP : ChatBigEmptyView.EMPTY_VIEW_TYPE_SAVED); emptyViewContainer.addView(bigEmptyView, new FrameLayout.LayoutParams(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); if (currentChat != null) { @@ -2987,7 +3115,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { emptyView.setText(LocaleController.getString("NoReplies", R.string.NoReplies)); } - } else if (inScheduleMode) { + } else if (chatMode == MODE_SCHEDULED) { emptyView.setText(LocaleController.getString("NoScheduledMessages", R.string.NoScheduledMessages)); } else if (currentUser != null && currentUser.id != 777000 && currentUser.id != 429000 && currentUser.id != 4244000 && MessagesController.isSupportUser(currentUser)) { emptyView.setText(LocaleController.getString("GotAQuestion", R.string.GotAQuestion)); @@ -3046,7 +3174,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean wasTrackingVibrate; private float replyButtonProgress; private long lastReplyButtonAnimationTime; - private float cilpTop; private boolean ignoreLayout; @@ -3064,12 +3191,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void setTranslationY(float translationY) { super.setTranslationY(translationY); if (emptyViewContainer != null) { - emptyViewContainer.setTranslationY(translationY / 2f); + emptyViewContainer.setTranslationY(translationY / 1.7f); } - invalidate(); + invalidateChatListViewTopPadding(); } - @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); @@ -3103,7 +3229,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int count = getChildCount(); for (int a = 0; a < count; a++) { View child = getChildAt(a); - if (child == this || !(child instanceof ChatMessageCell)) { + if (child == view || !(child instanceof ChatMessageCell)) { continue; } ChatMessageCell cell = (ChatMessageCell) child; @@ -3210,15 +3336,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (e != null && e.getAction() == MotionEvent.ACTION_DOWN && !startedTrackingSlidingView && !maybeStartTrackingSlidingView && slidingView == null) { View view = getPressedChildView(); if (view instanceof ChatMessageCell) { + if (slidingView != null) { + slidingView.setSlidingOffset(0); + } slidingView = (ChatMessageCell) view; MessageObject message = slidingView.getMessageObject(); - if (inScheduleMode || threadMessageObjects != null && threadMessageObjects.contains(message) || + if (chatMode != 0 || threadMessageObjects != null && threadMessageObjects.contains(message) || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || getMessageType(message) == 1 && (message.getDialogId() == mergeDialogId || message.needDrawBluredPreview()) || currentEncryptedChat == null && message.getId() < 0 || bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE || currentChat != null && (ChatObject.isNotInChat(currentChat) && !isThreadChat() || ChatObject.isChannel(currentChat) && !ChatObject.canPost(currentChat) && !currentChat.megagroup || !ChatObject.canSendMessages(currentChat)) || textSelectionHelper.isSelectionMode()) { + slidingView.setSlidingOffset(0); slidingView = null; return; } @@ -3307,7 +3437,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not protected void onChildPressed(View child, float x, float y, boolean pressed) { super.onChildPressed(child, x, y, pressed); if (child instanceof ChatMessageCell) { - MessageObject.GroupedMessages groupedMessages = ((ChatMessageCell) child).getCurrentMessagesGroup(); + ChatMessageCell chatMessageCell = (ChatMessageCell) child; + MessageObject object = chatMessageCell.getMessageObject(); + if (object.isMusic() || object.isDocument()) { + return; + } + MessageObject.GroupedMessages groupedMessages = chatMessageCell.getCurrentMessagesGroup(); if (groupedMessages != null) { int count = getChildCount(); for (int a = 0; a < count; a++) { @@ -3316,7 +3451,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not continue; } ChatMessageCell cell = (ChatMessageCell) item; - if (((ChatMessageCell) item).getCurrentMessagesGroup() == groupedMessages) { + if (cell.getCurrentMessagesGroup() == groupedMessages) { cell.setPressed(pressed); } } @@ -3349,6 +3484,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (trackAnimationProgress == 1f || trackAnimationProgress == 0f) { + slidingView.setSlidingOffset(0); slidingView = null; } invalidate(); @@ -3369,11 +3505,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject.GroupedMessages lastDrawnGroup = null; int count = getChildCount(); + canvas.save(); + canvas.clipRect(0, chatListViewPaddingTop - AndroidUtilities.dp(4), getMeasuredWidth(), getMeasuredHeight()); + for (int a = 0; a < count; a++) { View child = getChildAt(a); if (chatAdapter.isBot && child instanceof BotHelpCell) { BotHelpCell botCell = (BotHelpCell) child; - int top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListView.getPaddingTop(); + int top = getMeasuredHeight() / 2 - child.getMeasuredHeight() / 2 + chatListViewPaddingTop; if (!botCell.animating() && !chatListView.fastScrollAnimationRunning) { if (child.getTop() > top) { child.setTranslationY(top - child.getTop()); @@ -3459,14 +3598,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not View child = chatListView.getChildAt(i); if (child instanceof ChatMessageCell) { ChatMessageCell cell = (ChatMessageCell) child; - if (chatListView.isFastScrollAnimationRunning()) { - if (child.getY() > chatListView.getHeight() || child.getY() + child.getHeight() < 0) { - continue; - } - } else { - if (child.getTop() > chatListView.getHeight() || child.getTop() + child.getHeight() < 0) { - continue; - } + if (child.getY() > chatListView.getHeight() || child.getY() + child.getHeight() < 0) { + continue; } MessageObject.GroupedMessages group = cell.getCurrentMessagesGroup(); if (group == null || (k == 0 && group.messages.size() == 1) || (k == 1 && !group.transitionParams.drawBackgroundForDeletedItems)) { @@ -3491,19 +3624,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not drawingGroups.add(group); } - if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_TOP) != 0) { - group.transitionParams.pinnedTop = cell.isPinnedTop(); - } - if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { - group.transitionParams.pinnedBotton = cell.isPinnedBottom(); - } - + group.transitionParams.pinnedTop = cell.isPinnedTop(); + group.transitionParams.pinnedBotton = cell.isPinnedBottom(); int left = (cell.getLeft() + cell.getBackgroundDrawableLeft()); int right = (cell.getLeft() + cell.getBackgroundDrawableRight()); int top = (cell.getTop() + cell.getBackgroundDrawableTop()); int bottom = (cell.getTop() + cell.getBackgroundDrawableBottom()); + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_TOP) == 0) { + top -= AndroidUtilities.dp(10); + } + + if ((cell.getCurrentPosition().flags & MessageObject.POSITION_FLAG_BOTTOM) == 0) { + bottom += AndroidUtilities.dp(10); + } + if (cell.willRemovedAfterAnimation()) { group.transitionParams.cell = cell; } @@ -3526,7 +3662,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int i = 0; i < drawingGroups.size(); i++) { MessageObject.GroupedMessages group = drawingGroups.get(i); if (group == scrimGroup) { - group.transitionParams.cell = null; continue; } float x = group.transitionParams.cell.getNonAnimationTranslationX(true); @@ -3540,6 +3675,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not b += group.transitionParams.cell.getTranslationY(); } + if (t < chatListViewPaddingTop - AndroidUtilities.dp(20)) { + t = chatListViewPaddingTop - AndroidUtilities.dp(20); + } + + if (b > chatListView.getMeasuredHeight() + AndroidUtilities.dp(20)) { + b = chatListView.getMeasuredHeight() + AndroidUtilities.dp(20); + } + boolean useScale = group.transitionParams.cell.getScaleX() != 1f || group.transitionParams.cell.getScaleY() != 1f; if (useScale) { canvas.save(); @@ -3563,12 +3706,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - canvas.save(); - cilpTop = actionBar.getY() + actionBar.getMeasuredHeight() - getY(); - if (pinnedMessageView != null) { - cilpTop += Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); - } - canvas.clipRect(0, cilpTop, getMeasuredWidth(), getMeasuredHeight()); super.dispatchDraw(canvas); canvas.restore(); } @@ -3579,6 +3716,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int clipBottom = 0; boolean skipDraw = child == scrimView; ChatMessageCell cell; + float cilpTop = chatListViewPaddingTop - AndroidUtilities.dp(4); if (child.getY() > getMeasuredHeight() || child.getY() + child.getMeasuredHeight() < cilpTop) { skipDraw = true; @@ -3606,15 +3744,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not skipDraw = true; } } + if (skipDraw) { + cell.getPhotoImage().skipDraw(); + } } else { cell = null; } if (clipLeft != 0) { canvas.save(); - //canvas.clipRect(clipLeft + child.getTranslationX(), child.getTop(), child.getRight() + child.getTranslationX(), child.getBottom()); } else if (clipBottom != 0) { canvas.save(); - //canvas.clipRect(child.getLeft() + child.getTranslationX(), child.getTop(), child.getRight() + child.getTranslationX(), clipBottom); } boolean result; if (!skipDraw) { @@ -3678,7 +3817,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cell = drawTimeAfter.get(a); canvas.save(); canvas.translate(cell.getLeft() + cell.getNonAnimationTranslationX(false), cell.getY()); - cell.drawTime(canvas, cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f); + cell.drawTime(canvas, cell.shouldDrawAlphaLayer() ? cell.getAlpha() : 1f, true); canvas.restore(); } drawTimeAfter.clear(); @@ -3693,7 +3832,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not canvas.save(); canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); cell.drawNamesLayout(canvas, alpha); + cell.setInvalidatesParent(false); canvas.restore(); } drawNamesAfter.clear(); @@ -3752,12 +3893,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not float canvasOffsetY = chatMessageCell.getTop(); canvas.save(); canvas.translate(canvasOffsetX, canvasOffsetY); + cell.setInvalidatesParent(true); if (position == null || position.last) { - chatMessageCell.drawTime(canvas, alpha); + chatMessageCell.drawTime(canvas, alpha, true); } if (position == null || (position.minX == 0 && position.minY == 0)) { chatMessageCell.drawNamesLayout(canvas, alpha); } + cell.setInvalidatesParent(false); canvas.restore(); } else { if (position == null || position.last) { @@ -3808,7 +3951,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (videoPlayerContainer != null && (message.isRoundVideo() || message.isVideo()) && MediaController.getInstance().isPlayingMessage(message)) { ImageReceiver imageReceiver = chatMessageCell.getPhotoImage(); float newX = imageReceiver.getImageX() + chatMessageCell.getX(); - float newY = fragmentView.getPaddingTop() + chatMessageCell.getY() + imageReceiver.getImageY() - chatListViewClipTop + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0); + float newY = fragmentView.getPaddingTop() + chatMessageCell.getY() + imageReceiver.getImageY() + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0); if (videoPlayerContainer.getTranslationX() != newX || videoPlayerContainer.getTranslationY() != newY) { videoPlayerContainer.setTranslationX(newX); videoPlayerContainer.setTranslationY(newY); @@ -3829,7 +3972,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean replaceAnimation = chatListView.isFastScrollAnimationRunning() || (groupedMessages != null && groupedMessages.transitionParams.backgroundChangeBounds); int top = replaceAnimation ? child.getTop() : (int) child.getY(); - if (chatMessageCell.isPinnedBottom()) { + if (chatMessageCell.drawPinnedBottom()) { int p; if (chatMessageCell.willRemovedAfterAnimation()) { p = chatScrollHelper.positionToOldView.indexOfValue(child); @@ -3894,7 +4037,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!replaceAnimation && child.getTranslationY() != 0) { canvas.restore(); } - if (chatMessageCell.isPinnedTop()) { + if (chatMessageCell.drawPinnedTop()) { int p; if (chatMessageCell.willRemovedAfterAnimation()) { p = chatScrollHelper.positionToOldView.indexOfValue(child); @@ -3941,7 +4084,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not top = view.getTop(); if (view instanceof ChatMessageCell) { cell = (ChatMessageCell) view; - if (!cell.isPinnedTop()) { + if (!cell.drawPinnedTop()) { break; } else { p = prevPosition; @@ -3958,7 +4101,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not top = holder.itemView.getTop(); if (holder.itemView instanceof ChatMessageCell) { cell = (ChatMessageCell) holder.itemView; - if (!cell.isPinnedTop()) { + if (!cell.drawPinnedTop()) { break; } else { p = prevPosition; @@ -3976,7 +4119,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (y - AndroidUtilities.dp(48) < top) { y = top + AndroidUtilities.dp(48); } - if (!chatMessageCell.isPinnedBottom()) { + if (!chatMessageCell.drawPinnedBottom()) { int cellBottom = replaceAnimation ? chatMessageCell.getBottom() : (int) (chatMessageCell.getY() + chatMessageCell.getMeasuredHeight()); if (y > cellBottom) { y = cellBottom; @@ -4050,6 +4193,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setAdapter(chatAdapter = new ChatActivityAdapter(context)); chatListView.setClipToPadding(false); chatListView.setAnimateEmptyView(true, 1); + chatListView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); chatListViewPaddingTop = 0; invalidateChatListViewTopPadding(); if (MessagesController.getGlobalMainSettings().getBoolean("view_animations", true)) { @@ -4061,7 +4205,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationStart() { if (index == -1) { - index = getNotificationCenter().setAnimationInProgress(index, allowedNotificationsDuringChatListAnimations); + index = getNotificationCenter().setAnimationInProgress(index, allowedNotificationsDuringChatListAnimations, false); } if (finishRunnable != null) { AndroidUtilities.cancelRunOnUIThread(finishRunnable); @@ -4079,6 +4223,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.cancelRunOnUIThread(finishRunnable); } AndroidUtilities.runOnUIThread(finishRunnable = () -> { + if (nextScrollToMessageId != 0) { + scrollToMessageId(nextScrollToMessageId, nextScrollFromMessageId, nextScrollSelect, nextScrollLoadIndex, nextScrollForce); + nextScrollToMessageId = 0; + } if (index != -1) { getNotificationCenter().onAnimationFinish(index); index = -1; @@ -4111,6 +4259,74 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatLayoutManager = new GridLayoutManagerFixed(context, 1000, LinearLayoutManager.VERTICAL, true) { + + boolean computingScroll; + + @Override + public int getStarForFixGap() { + int padding = chatListViewPaddingTop; + if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); + } + return padding; + } + + @Override + protected int getParentStart() { + if (computingScroll) { + return chatListViewPaddingTop; + } + return 0; + } + + @Override + public int getStartAfterPadding() { + if (computingScroll) { + return chatListViewPaddingTop; + } + return super.getStartAfterPadding(); + } + + @Override + public int getTotalSpace() { + if (computingScroll) { + return getHeight() - chatListViewPaddingTop - getPaddingBottom(); + } + return super.getTotalSpace(); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + computingScroll = true; + int r = super.computeVerticalScrollExtent(state); + computingScroll = false; + return r; + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + computingScroll = true; + int r = super.computeVerticalScrollOffset(state); + computingScroll = false; + return r; + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + computingScroll = true; + int r = super.computeVerticalScrollRange(state); + computingScroll = false; + return r; + } + + @Override + public void scrollToPositionWithOffset(int position, int offset, boolean bottom) { + if (!bottom) { + offset = offset - getPaddingTop() + chatListViewPaddingTop; + } + super.scrollToPositionWithOffset(position, offset, bottom); + } + @Override public boolean supportsPredictiveItemAnimations() { return true; @@ -4173,6 +4389,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + int n = chatListView.getChildCount(); + for (int i = 0; i < n; i++) { + View child = chatListView.getChildAt(i); + int padding = chatListViewPaddingTop; + if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); + } + if (chatListView.getChildAdapterPosition(child) == chatAdapter.getItemCount() - 1) { + if (child.getTop() - dy > padding) { + dy = child.getTop() - padding; + } + return super.scrollVerticallyBy(dy, recycler, state); + } + } + return super.scrollVerticallyBy(dy, recycler, state); + } }; chatLayoutManager.setSpanSizeLookup(new GridLayoutManagerFixed.SpanSizeLookup() { @Override @@ -4275,8 +4510,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void onScrolled(RecyclerView recyclerView, int dx, int dy) { chatListView.invalidate(); scrollUp = dy < 0; - if (!wasManualScroll && dy != 0 && recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) { - wasManualScroll = true; + if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) { + if ((!scrollUp || forceScrollToFirst) && forceNextPinnedMessageId != 0) { + forceNextPinnedMessageId = 0; + } + forceScrollToFirst = false; + if (!wasManualScroll && dy != 0) { + wasManualScroll = true; + } } if (dy != 0) { hideHints(true); @@ -4320,7 +4561,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - updateMessagesVisiblePart(true); + invalidateMessagesVisiblePart(); textSelectionHelper.onParentScrolled(); } }); @@ -4422,7 +4663,63 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); if (currentEncryptedChat == null) { - pinnedMessageView = new FrameLayout(context); + pinnedMessageView = new FrameLayout(context) { + + float lastY; + float startY; + + { + setOnLongClickListener(v -> { + if (AndroidUtilities.isTablet() || isThreadChat()) { + return false; + } + startY = lastY; + openPinnedMessagesList(true); + return true; + }); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + lastY = event.getY(); + if (event.getAction() == MotionEvent.ACTION_UP) { + finishPreviewFragment(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + float dy = startY - lastY; + movePreviewFragment(dy); + if (dy < 0) { + startY = lastY; + } + } + return super.onTouchEvent(event); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (setPinnedTextTranslationX) { + for (int a = 0; a < pinnedNextAnimation.length; a++) { + if (pinnedNextAnimation[a] != null) { + pinnedNextAnimation[a].start(); + } + } + setPinnedTextTranslationX = false; + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + if (child == pinnedLineView) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), AndroidUtilities.dp(48)); + } + boolean result = super.drawChild(canvas, child, drawingTime); + if (child == pinnedLineView) { + canvas.restore(); + } + return result; + } + }; pinnedMessageView.setTag(1); pinnedMessageEnterOffset = -AndroidUtilities.dp(50); pinnedMessageView.setVisibility(View.GONE); @@ -4430,13 +4727,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pinnedMessageView.getBackground().setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelBackground), PorterDuff.Mode.SRC_IN)); contentView.addView(pinnedMessageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.TOP | Gravity.LEFT)); pinnedMessageView.setOnClickListener(v -> { + if (chatListView.isFastScrollAnimationRunning()) { //TODO remove later + return; + } wasManualScroll = true; if (isThreadChat()) { scrollToMessageId(threadMessageId, 0, true, 0, true); - } else if (chatInfo != null) { - scrollToMessageId(chatInfo.pinned_msg_id, 0, true, 0, true); - } else if (userInfo != null) { - scrollToMessageId(userInfo.pinned_msg_id, 0, true, 0, true); + } else if (currentPinnedMessageId != 0) { + int currentPinned; + /*if (forceNextPinnedMessageId != 0 && chatListView.isFastScrollAnimationRunning()) { + currentPinned = findClosest(pinnedMessageIds, forceNextPinnedMessageId, currentPinnedMessageIndex); + } else {*/ + currentPinned = currentPinnedMessageId; + //} + scrollToMessageId(currentPinned, 0, true, 0, true); + if (!pinnedMessageIds.isEmpty()) { + if (currentPinned == pinnedMessageIds.get(pinnedMessageIds.size() - 1)) { + forceNextPinnedMessageId = pinnedMessageIds.get(0) + 1; + forceScrollToFirst = true; + } else { + forceNextPinnedMessageId = currentPinned - 1; + forceScrollToFirst = false; + } + updateMessagesVisiblePart(false); + } } }); @@ -4444,23 +4758,76 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selector.setBackground(Theme.getSelectorDrawable(false)); pinnedMessageView.addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 2)); - pinnedLineView = new View(context); - pinnedLineView.setBackgroundColor(Theme.getColor(Theme.key_chat_topPanelLine)); - pinnedMessageView.addView(pinnedLineView, LayoutHelper.createFrame(2, 32, Gravity.LEFT | Gravity.TOP, 8, 8, 0, 0)); + pinnedLineView = new PinnedLineView(context); + pinnedMessageView.addView(pinnedLineView, LayoutHelper.createFrame(2, 48, Gravity.LEFT | Gravity.TOP, 8, 0, 0, 0)); - pinnedMessageImageView = new BackupImageView(context); - pinnedMessageView.addView(pinnedMessageImageView, LayoutHelper.createFrame(32, 32, Gravity.TOP | Gravity.LEFT, 17, 8, 0, 0)); + pinnedCounterTextView = new NumberTextView(context); + pinnedCounterTextView.setAddNumber(); + pinnedCounterTextView.setTextSize(14); + pinnedCounterTextView.setTextColor(Theme.getColor(Theme.key_chat_topPanelTitle)); + pinnedCounterTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + pinnedMessageView.addView(pinnedCounterTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 7, 44, 0)); - pinnedMessageNameTextView = new SimpleTextView(context); - pinnedMessageNameTextView.setTextSize(14); - pinnedMessageNameTextView.setTextColor(Theme.getColor(Theme.key_chat_topPanelTitle)); - pinnedMessageNameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - pinnedMessageView.addView(pinnedMessageNameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(18), Gravity.TOP | Gravity.LEFT, 18, 7.3f, 40, 0)); + for (int a = 0; a < 2; a++) { + pinnedNameTextView[a] = new SimpleTextView(context) { + @Override + protected boolean createLayout(int width) { + boolean result = super.createLayout(width); + if (this == pinnedNameTextView[0] && pinnedCounterTextView != null) { + int newX = getTextWidth() + AndroidUtilities.dp(4); + if (newX != pinnedCounterTextViewX) { + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX = newX); + } + } + return result; + } + }; + pinnedNameTextView[a].setTextSize(14); + pinnedNameTextView[a].setTextColor(Theme.getColor(Theme.key_chat_topPanelTitle)); + pinnedNameTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + pinnedMessageView.addView(pinnedNameTextView[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 7.3f, 44, 0)); - pinnedMessageTextView = new SimpleTextView(context); - pinnedMessageTextView.setTextSize(14); - pinnedMessageTextView.setTextColor(Theme.getColor(Theme.key_chat_topPanelMessage)); - pinnedMessageView.addView(pinnedMessageTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(18), Gravity.TOP | Gravity.LEFT, 18, 25.3f, 40, 0)); + pinnedMessageTextView[a] = new SimpleTextView(context) { + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + if (this == pinnedMessageTextView[0] && pinnedNextAnimation[1] != null) { + if (forceScrollToFirst && translationY < 0) { + pinnedLineView.setTranslationY(translationY / 2); + } else { + pinnedLineView.setTranslationY(0); + } + } + } + }; + pinnedMessageTextView[a].setTextSize(14); + pinnedMessageTextView[a].setTextColor(Theme.getColor(Theme.key_chat_topPanelMessage)); + pinnedMessageView.addView(pinnedMessageTextView[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 18, 25.3f, 44, 0)); + + pinnedMessageImageView[a] = new BackupImageView(context); + pinnedMessageImageView[a].setRoundRadius(AndroidUtilities.dp(2)); + pinnedMessageView.addView(pinnedMessageImageView[a], LayoutHelper.createFrame(32, 32, Gravity.TOP | Gravity.LEFT, 17, 8, 0, 0)); + if (a == 1) { + pinnedMessageTextView[a].setVisibility(View.INVISIBLE); + pinnedNameTextView[a].setVisibility(View.INVISIBLE); + pinnedMessageImageView[a].setVisibility(View.INVISIBLE); + } + } + + pinnedListButton = new ImageView(context); + pinnedListButton.setImageResource(R.drawable.menu_pinnedlist); + pinnedListButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelClose), PorterDuff.Mode.MULTIPLY)); + pinnedListButton.setScaleType(ImageView.ScaleType.CENTER); + pinnedListButton.setContentDescription(LocaleController.getString("AccPinnedMessagesList", R.string.AccPinnedMessagesList)); + pinnedListButton.setVisibility(View.INVISIBLE); + pinnedListButton.setAlpha(0.0f); + pinnedListButton.setScaleX(0.4f); + pinnedListButton.setScaleY(0.4f); + if (Build.VERSION.SDK_INT >= 21) { + pinnedListButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_inappPlayerClose) & 0x19ffffff)); + } + pinnedMessageView.addView(pinnedListButton, LayoutHelper.createFrame(36, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 7, 0)); + pinnedListButton.setOnClickListener(v -> openPinnedMessagesList(false)); closePinned = new ImageView(context); closePinned.setImageResource(R.drawable.miniplayer_close); @@ -4473,7 +4840,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (Build.VERSION.SDK_INT >= 21) { closePinned.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_inappPlayerClose) & 0x19ffffff, 1, AndroidUtilities.dp(14))); } - pinnedMessageView.addView(closePinned, LayoutHelper.createFrame(36, 48, Gravity.RIGHT | Gravity.TOP)); + pinnedMessageView.addView(closePinned, LayoutHelper.createFrame(36, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 2, 0)); closePinned.setOnClickListener(v -> { if (getParentActivity() == null) { return; @@ -4494,7 +4861,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("UnpinMessageAlertTitle", R.string.UnpinMessageAlertTitle)); builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("UnpinMessage", R.string.UnpinMessage), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); + builder.setPositiveButton(LocaleController.getString("UnpinMessage", R.string.UnpinMessage), (dialogInterface, i) -> { + MessageObject messageObject = pinnedMessageObjects.get(currentPinnedMessageId); + if (messageObject == null) { + messageObject = messagesDict[0].get(currentPinnedMessageId); + } + unpinMessage(messageObject); + }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); builder.setNeutralButton(LocaleController.getString("Hide", R.string.Hide), (dialogInterface, i) -> { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); @@ -4506,13 +4879,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updatePinnedMessageView(true); }); showDialog(builder.create()); - } else { + } else if (!pinnedMessageIds.isEmpty()) { SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); - if (chatInfo != null) { - preferences.edit().putInt("pin_" + dialog_id, chatInfo.pinned_msg_id).apply(); - } else if (userInfo != null) { - preferences.edit().putInt("pin_" + dialog_id, userInfo.pinned_msg_id).apply(); - } + preferences.edit().putInt("pin_" + dialog_id, pinnedMessageIds.get(0)).commit(); updatePinnedMessageView(true); } }); @@ -4635,7 +5004,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } closeReportSpam.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_chat_topPanelClose), PorterDuff.Mode.SRC_IN)); closeReportSpam.setScaleType(ImageView.ScaleType.CENTER); - topChatPanelView.addView(closeReportSpam, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); + topChatPanelView.addView(closeReportSpam, LayoutHelper.createFrame(36, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 2, 0)); closeReportSpam.setOnClickListener(v -> { long did = dialog_id; if (currentEncryptedChat != null) { @@ -4682,6 +5051,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scrollToMessageId(returnToMessageId, 0, true, returnToLoadIndex, true); } else { scrollToLastMessage(); + if (!pinnedMessageIds.isEmpty()) { + forceScrollToFirst = true; + forceNextPinnedMessageId = pinnedMessageIds.get(0); + } } }); @@ -5125,7 +5498,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } })); - if (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup) { + if (!ChatObject.isChannel(currentChat) || currentChat.megagroup) { mentionsAdapter.setBotInfo(botInfo); } mentionsAdapter.setParentFragment(this); @@ -5140,25 +5513,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Object object = mentionsAdapter.getItem(position); int start = mentionsAdapter.getResultStartPosition(); int len = mentionsAdapter.getResultLength(); - if (object instanceof TLRPC.User) { + if (object instanceof TLRPC.Chat) { if (searchingForUser && searchContainer.getVisibility() == View.VISIBLE) { - searchUserMessages((TLRPC.User) object); + searchUserMessages(null, (TLRPC.Chat) object); + } + } else if (object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) object; + if (searchingForUser && searchContainer.getVisibility() == View.VISIBLE) { + searchUserMessages(user, null); } else { - TLRPC.User user = (TLRPC.User) object; - if (user != null) { - if (user.username != null) { - chatActivityEnterView.replaceWithText(start, len, "@" + user.username + " ", false); - } else { - String name = UserObject.getFirstName(user, false); - Spannable spannable = new SpannableString("@" + name + " "); - spannable.setSpan(new URLSpanUserMention("" + user.id, 3), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - chatActivityEnterView.replaceWithText(start, len, spannable, false); - } + if (user.username != null) { + chatActivityEnterView.replaceWithText(start, len, "@" + user.username + " ", false); + } else { + String name = UserObject.getFirstName(user, false); + Spannable spannable = new SpannableString("@" + name + " "); + spannable.setSpan(new URLSpanUserMention("" + user.id, 3), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + chatActivityEnterView.replaceWithText(start, len, spannable, false); } } } else if (object instanceof String) { if (mentionsAdapter.isBotCommands()) { - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> { getSendMessagesHelper().sendMessage((String) object, dialog_id, replyingMessageObject, getThreadMessage(), null, false, null, null, null, notify, scheduleDate); chatActivityEnterView.setFieldText(""); @@ -5176,7 +5551,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.replaceWithText(start, len, object + " ", false); } } else if (object instanceof TLRPC.BotInlineResult) { - if (chatActivityEnterView.getFieldText() == null || !inScheduleMode && checkSlowMode(view)) { + if (chatActivityEnterView.getFieldText() == null || chatMode != MODE_SCHEDULED && checkSlowMode(view)) { return; } TLRPC.BotInlineResult result = (TLRPC.BotInlineResult) object; @@ -5187,7 +5562,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not PhotoViewer.getInstance().setParentActivity(getParentActivity()); PhotoViewer.getInstance().openPhotoForSelect(arrayList, mentionsAdapter.getItemPosition(position), 3, false, botContextProvider, ChatActivity.this); } else { - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> sendBotInlineResult(result, notify, scheduleDate)); } else { sendBotInlineResult(result, true, 0); @@ -5338,8 +5713,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentiondownButton.setContentDescription(LocaleController.getString("AccDescrMentionDown", R.string.AccDescrMentionDown)); if (!AndroidUtilities.isTablet() || AndroidUtilities.isSmallTablet()) { - contentView.addView(fragmentLocationContextView = new FragmentContextView(context, this, true), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); - contentView.addView(fragmentContextView = new FragmentContextView(context, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + contentView.addView(fragmentLocationContextView = new FragmentContextView(context, this, true), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + contentView.addView(fragmentContextView = new FragmentContextView(context, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); fragmentContextView.setAdditionalContextView(fragmentLocationContextView); fragmentLocationContextView.setAdditionalContextView(fragmentContextView); } @@ -5439,9 +5814,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - + public void checkAnimation() { if (actionBar.isActionModeShowed()) { if (messageEditTextAnimator != null) { messageEditTextAnimator.cancel(); @@ -5469,7 +5842,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not topLineView.setTranslationY(animatedTop); } } - contentView.setClipChildren(false); changeBoundAnimator = ValueAnimator.ofFloat(1f, 0); changeBoundAnimator.addUpdateListener(a -> { @@ -5492,8 +5864,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView.setTranslationY(v); invalidateChatListViewTopPadding(); - updateChatListViewTopPadding(); - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); } invalidate(); }); @@ -5509,7 +5880,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { chatListView.setTranslationY(0); } - contentView.setClipChildren(true); changeBoundAnimator = null; } }); @@ -5522,7 +5892,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not changeBoundAnimator.start(); } invalidateChatListViewTopPadding(); - updateMessagesVisiblePart(true); + invalidateMessagesVisiblePart(); chatActivityEnterViewAnimateFromTop = 0; } else if (lastContentViewHeight != contentView.getMeasuredHeight()) { chatActivityEnterViewAnimateFromTop = 0; @@ -5551,15 +5921,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected void onLineCountChanged(int oldLineCount, int newLineCount) { if (chatActivityEnterView != null) { - if (!TextUtils.isEmpty(messageEditText.getText())) { - shouldAnimateEditTextWithBounds = true; - messageEditTextPredrawHeigth = messageEditText.getMeasuredHeight(); - messageEditTextPredrawScrollY = messageEditText.getScrollY(); - } else { - messageEditText.animate().cancel(); - messageEditText.setOffsetY(0); - shouldAnimateEditTextWithBounds = false; - } + shouldAnimateEditTextWithBounds = true; + messageEditTextPredrawHeigth = messageEditText.getMeasuredHeight(); + messageEditTextPredrawScrollY = messageEditText.getScrollY(); contentView.invalidate(); chatActivityEnterViewAnimateFromTop = chatActivityEnterView.getBackgroundTop(); } @@ -5848,7 +6212,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean hasScheduledMessages() { - return scheduledMessagesCount > 0 && !inScheduleMode; + return scheduledMessagesCount > 0 && chatMode == 0; } @Override @@ -5870,6 +6234,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void bottomPanelTranslationYChanged(float translation) { + if (translation != 0) { + wasManualScroll = true; + } bottomPanelTranslationY = chatActivityEnterView.pannelAniamationInProgress() ? chatActivityEnterView.getEmojiPadding() - translation : 0; chatActivityEnterView.setTranslationY(translation); @@ -5883,7 +6250,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentiondownButton.setTranslationY(pagedownButton.getVisibility() != View.VISIBLE ? translation : translation - AndroidUtilities.dp(72)); } invalidateChatListViewTopPadding(); - updateChatListViewTopPadding(); + invalidateMessagesVisiblePart(); updateTextureViewPosition(false); contentView.invalidate(); } @@ -5892,6 +6259,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not public void prepareMessageSending() { waitingForSendingMessageLoad = true; } + + @Override + public void onTrendingStickersShowed(boolean show) { + if (show) { + AndroidUtilities.setAdjustResizeToNothing(getParentActivity(), classGuid); + fragmentView.requestLayout(); + } else { + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + } }); chatActivityEnterView.setDialogId(dialog_id, currentAccount); if (chatInfo != null) { @@ -5926,11 +6303,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (pagedownButton != null) { pagedownButton.setTranslationY(translationY); + if (mentiondownButton != null) { + mentiondownButton.setTranslationY(pagedownButton.getVisibility() != VISIBLE ? translationY : translationY - AndroidUtilities.dp(72)); + } } - if (mentiondownButton != null) { - mentiondownButton.setTranslationY(pagedownButton.getVisibility() != VISIBLE ? translationY : translationY - AndroidUtilities.dp(72)); - } - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); if (fragmentView != null) { fragmentView.invalidate(); } @@ -6034,6 +6411,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyLayout.addView(replyObjectTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 18, Gravity.TOP | Gravity.LEFT, 52, 24, 52, 0)); replyImageView = new BackupImageView(context); + replyImageView.setRoundRadius(AndroidUtilities.dp(2)); replyLayout.addView(replyImageView, LayoutHelper.createFrame(34, 34, Gravity.TOP | Gravity.LEFT, 52, 6, 0, 0)); stickersPanel = new FrameLayout(context); @@ -6058,7 +6436,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public boolean isInScheduleMode() { - return inScheduleMode; + return chatMode == MODE_SCHEDULED; } @Override @@ -6158,10 +6536,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchUpButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), 1)); searchContainer.addView(searchUpButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 48, 0)); searchUpButton.setOnClickListener(view -> { - if (chatListView.isFastScrollAnimationRunning()) { - return; - } - getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, threadMessageId, searchingUserMessages); + getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 1, threadMessageId, searchingUserMessages, searchingChatMessages); showMessagesSearchListView(false); if (!SharedConfig.searchMessagesAsListUsed && SharedConfig.searchMessagesAsListHintShows < 3 && !searchAsListHintShown && Math.random() <= 0.25) { showSearchAsListHint(); @@ -6178,10 +6553,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchDownButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), 1)); searchContainer.addView(searchDownButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP, 0, 0, 0, 0)); searchDownButton.setOnClickListener(view -> { - if (chatListView.isFastScrollAnimationRunning()) { - return; - } - getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, threadMessageId, searchingUserMessages); + getMediaDataController().searchMessagesInChat(null, dialog_id, mergeDialogId, classGuid, 2, threadMessageId, searchingUserMessages, searchingChatMessages); showMessagesSearchListView(false); }); searchDownButton.setContentDescription(LocaleController.getString("AccDescrSearchPrev", R.string.AccDescrSearchPrev)); @@ -6200,6 +6572,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchUserButton.setVisibility(View.GONE); searchingForUser = true; searchingUserMessages = null; + searchingChatMessages = null; searchItem.setSearchFieldHint(LocaleController.getString("SearchMembers", R.string.SearchMembers)); searchItem.setSearchFieldCaption(LocaleController.getString("SearchFrom", R.string.SearchFrom)); AndroidUtilities.showKeyboard(searchItem.getSearchField()); @@ -6285,7 +6658,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null) { return; } - if (currentUser != null && userBlocked) { + if (chatMode == MODE_PINNED) { + finishFragment(); + chatActivityDelegate.onUnpin(true, bottomOverlayChatText.getTag() == null); + } else if (currentUser != null && userBlocked) { if (currentUser.bot) { String botUserLast = botUser; botUser = null; @@ -6431,7 +6807,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateDistanceView(false); chatScrollHelper = new RecyclerAnimationScrollHelper(chatListView, chatLayoutManager); - chatScrollHelper.setScrollListener(() -> updateMessagesVisiblePart(false)); + chatScrollHelper.setScrollListener(this::invalidateMessagesVisiblePart); chatScrollHelper.setAnimationCallback(chatScrollHelperCallback); try { @@ -6477,12 +6853,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.addView(fireworksOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); textSelectionHelper.setParentView(chatListView); - if (getArguments().containsKey("search_from_user_id")) { - TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(getArguments().getInt("search_from_user_id")); + int searchFromUserId = getArguments().getInt("search_from_user_id", 0); + int searchFromChatId = getArguments().getInt("search_from_chat_id", 0); + if (searchFromUserId != 0) { + TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(searchFromUserId); if (user != null) { openSearchWithText(""); searchUserButton.callOnClick(); - searchUserMessages(user); + searchUserMessages(user, null); + } + } else if (searchFromChatId != 0) { + TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(searchFromChatId); + if (chat != null) { + openSearchWithText(""); + searchUserButton.callOnClick(); + searchUserMessages(null, chat); } } if (replyingMessageObject != null) { @@ -6491,14 +6876,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return fragmentView; } - private void searchUserMessages(TLRPC.User user) { + private void searchUserMessages(TLRPC.User user, TLRPC.Chat chat) { searchingUserMessages = user; - if (searchingUserMessages == null) { + searchingChatMessages = chat; + if (searchingUserMessages == null && searchingChatMessages == null) { return; } - String name = searchingUserMessages.first_name; - if (TextUtils.isEmpty(name)) { - name = searchingUserMessages.last_name; + String name; + if (searchingUserMessages != null) { + name = searchingUserMessages.first_name; + if (TextUtils.isEmpty(name)) { + name = searchingUserMessages.last_name; + } + } else { + name = searchingChatMessages.title; + } + if (name.length() > 10) { + name = name.substring(0, 10); } searchingForUser = false; String from = LocaleController.getString("SearchFrom", R.string.SearchFrom); @@ -6508,7 +6902,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionsAdapter.searchUsernameOrHashtag(null, 0, null, false); searchItem.setSearchFieldHint(null); searchItem.clearSearchText(); - getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages); + getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); } Animator distanceViewAnimator; @@ -6555,6 +6949,133 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private void openPinnedMessagesList(boolean preview) { + if (getParentActivity() == null || parentLayout == null || parentLayout.getLastFragment() != this || pinnedMessageIds.isEmpty()) { + return; + } + Bundle bundle = new Bundle(); + if (currentChat != null) { + bundle.putInt("chat_id", currentChat.id); + } else { + bundle.putInt("user_id", currentUser.id); + } + bundle.putInt("chatMode", MODE_PINNED); + ChatActivity fragment = new ChatActivity(bundle); + fragment.pinnedMessageIds = new ArrayList<>(pinnedMessageIds); + fragment.pinnedMessageObjects = new HashMap<>(pinnedMessageObjects); + for (int a = 0, N = pinnedMessageIds.size(); a < N; a++) { + Integer id = pinnedMessageIds.get(a); + MessageObject object = pinnedMessageObjects.get(id); + MessageObject object2 = messagesDict[0].get(id); + if (object == null) { + object = object2; + } else if (object2 != null) { + object.mediaExists = object2.mediaExists; + object.attachPathExists = object2.attachPathExists; + } + if (object != null) { + fragment.pinnedMessageObjects.put(id, object); + } + } + fragment.loadedPinnedMessagesCount = loadedPinnedMessagesCount; + fragment.totalPinnedMessagesCount = totalPinnedMessagesCount; + fragment.pinnedEndReached = pinnedEndReached; + fragment.userInfo = userInfo; + fragment.chatInfo = chatInfo; + fragment.chatActivityDelegate = new ChatActivityDelegate() { + @Override + public void openReplyMessage(int mid) { + scrollToMessageId(mid, 0, true, 0, true); + } + + @Override + public void openSearch(String text) { + openSearchWithText(text); + } + + @Override + public void onUnpin(boolean all, boolean hide) { + if (all) { + ArrayList ids = new ArrayList<>(pinnedMessageIds); + ArrayList objects = new ArrayList<>(pinnedMessageObjects.values()); + if (hide) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().putInt("pin_" + dialog_id, pinnedMessageIds.get(0)).commit(); + updatePinnedMessageView(true); + } else { + getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialog_id, ids, false, null, null, 0, 0, true); + } + showPinBulletin = true; + int tag = ++pinBullerinTag; + int oldTotalPinnedCount = getPinnedMessagesCount(); + pinBulletin = BulletinFactory.createUnpinAllMessagesBulletin(ChatActivity.this, oldTotalPinnedCount, hide, + () -> { + if (hide) { + SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); + preferences.edit().remove("pin_" + dialog_id).commit(); + updatePinnedMessageView(true); + } else { + getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialog_id, ids, true, objects, null, 0, oldTotalPinnedCount, pinnedEndReached); + } + if (tag == pinBullerinTag) { + pinBulletin = null; + } + }, + () -> { + if (!hide) { + getMessagesController().unpinAllMessages(currentChat, currentUser); + } + if (tag == pinBullerinTag) { + pinBulletin = null; + } + }); + } else { + MessageObject messageObject = pinnedMessageObjects.get(currentPinnedMessageId); + if (messageObject == null) { + messageObject = messagesDict[0].get(currentPinnedMessageId); + } + unpinMessage(messageObject); + } + } + }; + if (preview) { + int w = (int) (fragmentView.getMeasuredWidth() / 6.0f); + int h = (int) (fragmentView.getMeasuredHeight() / 6.0f); + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + canvas.scale(1.0f / 6.0f, 1.0f / 6.0f); + fragmentView.draw(canvas); + Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(w, h) / 180)); + + if (blurredView == null) { + blurredView = new View(getParentActivity()); + contentView.addView(blurredView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } else { + int idx = contentView.indexOfChild(blurredView); + if (idx != contentView.getChildCount() - 1) { + contentView.removeView(blurredView); + contentView.addView(blurredView); + } + blurredView.setVisibility(View.VISIBLE); + } + + blurredView.setBackground(new BitmapDrawable(bitmap)); + blurredView.setAlpha(0.0f); + + presentFragmentAsPreview(fragment); + } else { + presentFragment(fragment, false); + } + } + + @Override + protected int getPreviewHeight() { + if (chatMode == MODE_PINNED && messages.size() == 2) { + return getHeightForMessage(messages.get(0)) + AndroidUtilities.dp(80) + ActionBar.getCurrentActionBarHeight(); + } + return super.getPreviewHeight(); + } + boolean animateTo; private void showProgressView(boolean show) { @@ -6632,31 +7153,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateChatListViewTopPadding() { - if (!invalidateChatListViewTopPadding) { + if (!invalidateChatListViewTopPadding || chatListView == null) { return; } float topPanelViewH = Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); float pinnedViewH = 0; - if (!isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + if (pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { pinnedViewH = Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); } - - int p = (int) (AndroidUtilities.dp(4) + contentPaddingTop + distanceTopViewOffset + topPanelViewH + pinnedViewH); - if (chatListView != null && chatLayoutManager != null && chatAdapter != null && chatLayoutManager.findLastVisibleItemPosition() == chatAdapter.getItemCount() - 1) { - p += contentPanTranslation + bottomPanelTranslationY; - if (bottomPanelTranslationY == 0 && contentPanTranslation == 0) { - p += contentView.getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !inBubbleMode ? chatActivityEnterView.getEmojiPadding() : contentView.getKeyboardHeight(); - } - if (!inPreviewMode && chatActivityEnterView != null) { - p += chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(51) - chatActivityEnterView.getAnimatedTop(); - } - } else { - p += contentView.getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !inBubbleMode ? chatActivityEnterView.getEmojiPadding() : contentView.getKeyboardHeight(); - if (!inPreviewMode && chatActivityEnterView != null) { - p += chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(51); + int oldPadding = chatListViewPaddingTop; + chatListViewPaddingTop = (int) (AndroidUtilities.dp(4) + contentPaddingTop + distanceTopViewOffset + topPanelViewH + pinnedViewH); + chatListViewPaddingTop += contentPanTranslation + bottomPanelTranslationY; + if (bottomPanelTranslationY == 0 && !chatActivityEnterView.pannelAniamationInProgress() && contentView.getLayoutParams().height < 0) { + chatListViewPaddingTop += contentView.getKeyboardHeight() <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow && !inBubbleMode ? chatActivityEnterView.getEmojiPadding() : contentView.getKeyboardHeight(); + } + if (!inPreviewMode && chatActivityEnterView != null) { + if (chatActivityEnterView.getAnimatedTop() != 0) { + chatListViewPaddingTop += chatActivityEnterView.getHeightWithTopView() - AndroidUtilities.dp(51) - chatActivityEnterView.getAnimatedTop(); + } else { + chatListViewPaddingTop -= chatListView.getTranslationY(); } } + int p = chatListView.getMeasuredHeight() * 2 / 3; + if (chatListView != null && chatLayoutManager != null && chatAdapter != null) { if (chatListView.getPaddingTop() != p) { int firstVisPos = chatLayoutManager.findFirstVisibleItemPosition(); @@ -6679,7 +7199,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatListView.setPadding(0, p, 0, AndroidUtilities.dp(3)); - chatListView.setTopGlowOffset(contentPaddingTop + chatListViewPaddingTop); if (firstVisPos != RecyclerView.NO_POSITION && scrollToMessageObject != null) { chatAdapter.updateRowsSafe(); @@ -6689,7 +7208,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); + } + + chatListView.setTopGlowOffset(chatListViewPaddingTop - AndroidUtilities.dp(4)); + + if (oldPadding != chatListViewPaddingTop) { + int n = chatListView.getChildCount(); + for (int i = 0; i < n; i++) { + View child = chatListView.getChildAt(i); + int adapterPosition = chatListView.getChildAdapterPosition(child); + if (adapterPosition == chatAdapter.getItemCount() - 1) { + int padding = chatListViewPaddingTop; + if (isThreadChat() && pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + padding -= Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); + } + if (child.getTop() > padding) { + chatListView.scrollBy(0, child.getTop() - padding); + } + break; + } + } + } + + if (!isThreadChat() && !wasManualScroll && unreadMessageObject != null && chatListView != null) { + chatListView.scrollBy(0, oldPadding - chatListViewPaddingTop); } } @@ -6699,6 +7242,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void invalidateChatListViewTopPadding() { invalidateChatListViewTopPadding = true; contentView.invalidate(); + chatListView.invalidate(); float topPanelViewH = Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); float pinnedViewH = 0; @@ -7067,7 +7611,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not waitingForLoad.add(lastLoadIndex); postponedScrollMessageId = 0; postponedScrollIsCanceled = false; - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, date, true, 0, classGuid, 4, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, date, true, 0, classGuid, 4, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); floatingDateView.setAlpha(0.0f); floatingDateView.setTag(null); } @@ -7124,11 +7668,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (getParentActivity() == null || chatAttachAlert == null) { return; } - if (chatAttachAlert != null) { - editingMessageObject = chatAttachAlert.getEditingMessageObject(); - } else { - editingMessageObject = null; - } + editingMessageObject = chatAttachAlert.getEditingMessageObject(); if (button == 8 || button == 7 || button == 4 && !chatAttachAlert.getPhotoLayout().getSelectedPhotos().isEmpty()) { if (button != 8) { chatAttachAlert.dismiss(); @@ -7208,16 +7748,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void doOnIdle(Runnable runnable) { - if (chatListItemAniamtor != null && chatListItemAniamtor.isRunning()) { - chatListItemAniamtor.runOnAnimationEnd(runnable); - } else { - runnable.run(); - } + ChatActivity.this.doOnIdle(runnable); } }); } } + public void doOnIdle(Runnable runnable) { + NotificationCenter.getInstance(currentAccount).doOnIdle(runnable); + } + public long getDialogId() { return dialog_id; } @@ -7245,7 +7785,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void afterMessageSend() { hideFieldPanel(false); - if (!inScheduleMode) { + if (chatMode == 0) { getMediaDataController().cleanDraft(dialog_id, threadMessageId, true); } } @@ -7326,7 +7866,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { bundle.putInt("user_id", currentUser.id); } - bundle.putBoolean("scheduled", true); + bundle.putInt("chatMode", MODE_SCHEDULED); ChatActivity fragment = new ChatActivity(bundle); fragment.chatActivityDelegate = new ChatActivityDelegate() { @Override @@ -7411,11 +7951,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Object item = stickersAdapter.getItem(position); Object parent = stickersAdapter.getItemParent(position); if (item instanceof TLRPC.TL_document) { - if (!inScheduleMode && checkSlowMode(view)) { + if (chatMode == 0 && checkSlowMode(view)) { return; } TLRPC.TL_document document = (TLRPC.TL_document) item; - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> SendMessagesHelper.getInstance(currentAccount).sendSticker(document, dialog_id, replyingMessageObject, getThreadMessage(), parent, notify, scheduleDate)); } else { getSendMessagesHelper().sendSticker(document, dialog_id, replyingMessageObject, getThreadMessage(), parent, true, 0); @@ -7457,7 +7997,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } else { SendMessagesHelper.getInstance(currentAccount).sendMessage(getUserConfig().getCurrentUser(), dialog_id, messageObject, getThreadMessage(), null, null, true, 0); - if (!inScheduleMode) { + if (chatMode == 0) { moveScrollToLastMessage(); } hideFieldPanel(false); @@ -7523,9 +8063,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (StrUtil.isBlank(str)) return; getSendMessagesHelper().sendMessage(str, dialog_id, null, null, null, false, null, null, null, true, 0); - if (!inScheduleMode) { - moveScrollToLastMessage(); - } + afterMessageSend(); hideFieldPanel(false); break; @@ -7587,7 +8125,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void showVoiceHint(boolean hide, boolean video) { - if (getParentActivity() == null || fragmentView == null || hide && voiceHintTextView == null || inScheduleMode) { + if (getParentActivity() == null || fragmentView == null || hide && voiceHintTextView == null || chatMode != 0) { return; } if (voiceHintTextView == null) { @@ -7719,7 +8257,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void showScheduledOrNoSoundHint() { - boolean disableNoSound = (UserObject.isUserSelf(currentUser) || (chatInfo != null && chatInfo.slowmode_next_send_date > 0) && !isInScheduleMode()); + boolean disableNoSound = (UserObject.isUserSelf(currentUser) || (chatInfo != null && chatInfo.slowmode_next_send_date > 0) && chatMode == 0); if (SharedConfig.scheduledOrNoSoundHintShows >= 3 || System.currentTimeMillis() % 4 != 0 || disableNoSound) { return; } @@ -8183,7 +8721,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not floatingDateAnimation.start(); } if (!scroll) { - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); hideDateDelay = 1000; } } @@ -8235,8 +8773,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public boolean isKeyboardVisible() { - int keyboardSize = SharedConfig.smoothKeyboard ? 0 : contentView.getKeyboardHeight(); - return keyboardSize > AndroidUtilities.dp(20); + return contentView.getKeyboardHeight() > AndroidUtilities.dp(20); } private void checkScrollForLoad(boolean scroll) { @@ -8257,24 +8794,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not loading = true; waitingForLoad.add(lastLoadIndex); if (messagesByDays.size() != 0) { - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, maxMessageId[0], 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, maxMessageId[0], 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } else { - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } } else if (mergeDialogId != 0 && !endReached[1]) { loading = true; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(mergeDialogId, 0, false, 50, maxMessageId[1], 0, !cacheEndReached[1], minDate[1], classGuid, 0, 0, false, inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(mergeDialogId, 0, false, 50, maxMessageId[1], 0, !cacheEndReached[1], minDate[1], classGuid, 0, 0, false, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } } if (visibleItemCount > 0 && !loadingForward && firstVisibleItem <= 10) { if (mergeDialogId != 0 && !forwardEndReached[1]) { waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(mergeDialogId, 0, false, 50, minMessageId[1], 0, true, maxDate[1], classGuid, 1, 0, false, inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(mergeDialogId, 0, false, 50, minMessageId[1], 0, true, maxDate[1], classGuid, 1, 0, false, chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); loadingForward = true; } else if (!forwardEndReached[0]) { waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, minMessageId[0], 0, true, maxDate[0], classGuid, 1, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 50, minMessageId[0], 0, true, maxDate[0], classGuid, 1, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); loadingForward = true; } } @@ -8637,7 +9174,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (arrayList == null || arrayList.isEmpty()) { return; } - if ((scheduleDate != 0) == inScheduleMode) { + if ((scheduleDate != 0) == (chatMode == MODE_SCHEDULED)) { waitingForSendingMessageLoad = true; } if (!fromMyName) { @@ -9139,6 +9676,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatListView.isFastScrollAnimationRunning()) { return; } + forceNextPinnedMessageId = 0; + forceScrollToFirst = false; chatScrollHelper.setScrollDirection(RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN); if (forwardEndReached[0] && first_unread_id == 0 && startLoadFromMessageId == 0) { if (chatLayoutManager.findFirstCompletelyVisibleItemPosition() == 0) { @@ -9165,7 +9704,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not waitingForLoad.clear(); waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, true, 0, classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, true, 0, classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } } @@ -9183,7 +9722,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (videoPlayerContainer != null && (messageObject.isRoundVideo() || messageObject.isVideo()) && MediaController.getInstance().isPlayingMessage(messageObject)) { ImageReceiver imageReceiver = messageCell.getPhotoImage(); videoPlayerContainer.setTranslationX(imageReceiver.getImageX() + messageCell.getX()); - videoPlayerContainer.setTranslationY(fragmentView.getPaddingTop() + messageCell.getY() + imageReceiver.getImageY() - chatListViewClipTop + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0)); + videoPlayerContainer.setTranslationY(fragmentView.getPaddingTop() + messageCell.getY() + imageReceiver.getImageY() + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0)); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) videoPlayerContainer.getLayoutParams(); if (messageObject.isRoundVideo()) { videoPlayerContainer.setTag(R.id.parent_tag, null); @@ -9242,6 +9781,62 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + public void invalidateMessagesVisiblePart() { + invalidateMessagesVisiblePart = true; + if (fragmentView != null) { + fragmentView.invalidate(); + } + } + + private Integer findClosest(ArrayList arrayList, int target, int[] index) { + if (arrayList.isEmpty()) { + return 0; + } + Integer val = arrayList.get(0); + if (target >= val) { + index[0] = 0; + return val; + } + int n = arrayList.size(); + val = arrayList.get(n - 1); + if (target <= val) { + index[0] = n - 1; + return val; + } + + int i = 0, j = n, mid = 0; + while (i < j) { + mid = (i + j) / 2; + + val = arrayList.get(mid); + if (val == target) { + index[0] = mid; + return val; + } + if (target < val) { + if (mid > 0) { + Integer val2 = arrayList.get(mid - 1); + if (target > val2) { + index[0] = mid - 1; + return val2; + } + } + i = mid + 1; + } else { + if (mid > 0) { + Integer val2 = arrayList.get(mid - 1); + if (target < val2) { + index[0] = mid; + return val; + } + } + j = mid; + } + } + index[0] = mid; + return arrayList.get(mid); + } + public void updateMessagesVisiblePart(boolean inLayout) { if (chatListView == null) { return; @@ -9254,8 +9849,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not View minChild = null; View minMessageChild = null; boolean foundTextureViewMessage = false; - boolean previousPinnedMessageVisible = replyMessageVisible; - replyMessageVisible = firstLoading; + boolean previousThreadMessageVisible = threadMessageVisible; + int previousPinnedMessageId = currentPinnedMessageId; + int maxVisibleId = Integer.MIN_VALUE; + threadMessageVisible = firstLoading; Integer currentReadMaxId; long threadId = threadMessageId; @@ -9271,27 +9868,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int maxPositiveUnreadId = Integer.MIN_VALUE; int maxNegativeUnreadId = Integer.MAX_VALUE; int maxUnreadDate = Integer.MIN_VALUE; - int lastVisibleId = currentEncryptedChat != null ? Integer.MAX_VALUE : Integer.MIN_VALUE; int recyclerChatViewHeight = (contentView.getHeightWithKeyboard() - (inPreviewMode ? 0 : AndroidUtilities.dp(48)) - chatListView.getTop()); if (contentView.getKeyboardHeight() == 0) { recyclerChatViewHeight -= chatActivityEnterView.getEmojiPadding(); } pollsToCheck.clear(); - float animatedTop = 0; - if (chatActivityEnterView != null && chatLayoutManager.findLastVisibleItemPosition() != chatAdapter.getItemCount() - 1) { - animatedTop = -chatActivityEnterView.getAnimatedTop(); - } + float cilpTop = chatListViewPaddingTop; for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); MessageObject messageObject = null; int top = (int) view.getY(); int bottom = top + view.getMeasuredHeight(); - if (bottom < 0 || top > chatListView.getMeasuredHeight()) { + if (bottom <= cilpTop || top > chatListView.getMeasuredHeight()) { continue; } if (view instanceof ChatMessageCell) { ChatMessageCell messageCell = (ChatMessageCell) view; + messageObject = messageCell.getMessageObject(); + maxVisibleId = Math.max(maxVisibleId, messageObject.getId()); int viewTop = top >= 0 ? 0 : -top; int viewBottom = messageCell.getMeasuredHeight(); @@ -9300,18 +9895,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } messageCell.setVisiblePart(viewTop, viewBottom - viewTop, recyclerChatViewHeight, contentView.getKeyboardHeight()); - messageObject = messageCell.getMessageObject(); - if (!replyMessageVisible && threadMessageObject != null && messageObject == threadMessageObject && messageCell.getBottom() > chatListView.getPaddingTop()) { - replyMessageVisible = true; + if (!threadMessageVisible && threadMessageObject != null && messageObject == threadMessageObject && messageCell.getBottom() > chatListViewPaddingTop) { + threadMessageVisible = true; } - boolean isVideo; - if (videoPlayerContainer != null && (isVideo = messageObject.isVideo() || messageObject.isRoundVideo()) && MediaController.getInstance().isPlayingMessage(messageObject)) { + if (videoPlayerContainer != null && (messageObject.isVideo() || messageObject.isRoundVideo()) && MediaController.getInstance().isPlayingMessage(messageObject)) { ImageReceiver imageReceiver = messageCell.getPhotoImage(); - if (isVideo && top + imageReceiver.getImageY2() < 0) { + if (top + imageReceiver.getImageY2() < 0) { foundTextureViewMessage = false; } else { videoPlayerContainer.setTranslationX(imageReceiver.getImageX() + messageCell.getX()); - videoPlayerContainer.setTranslationY(fragmentView.getPaddingTop() + top + imageReceiver.getImageY() - chatListViewClipTop + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0)); + videoPlayerContainer.setTranslationY(fragmentView.getPaddingTop() + top + imageReceiver.getImageY() + chatListView.getTranslationY() + (inPreviewMode ? AndroidUtilities.statusBarHeight : 0)); fragmentView.invalidate(); videoPlayerContainer.invalidate(); foundTextureViewMessage = true; @@ -9319,10 +9912,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (view instanceof ChatActionCell) { messageObject = ((ChatActionCell) view).getMessageObject(); + if (messageObject != null) { + maxVisibleId = Math.max(maxVisibleId, messageObject.getId()); + } } else if (view instanceof BotHelpCell) { view.invalidate(); } - if (!inScheduleMode && messageObject != null) { + if (chatMode != MODE_SCHEDULED && messageObject != null) { int id = messageObject.getId(); if (!isThreadChat() && (!messageObject.isOut() && messageObject.isUnread() || messageObject.messageOwner.from_scheduled && id > currentReadMaxId) || id > 0 && isThreadChat() && id > currentReadMaxId && id > replyMaxReadId) { if (id > 0) { @@ -9337,12 +9933,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not pollsToCheck.add(messageObject); } } - if (view.getBottom() <= chatListView.getPaddingTop() + AndroidUtilities.dp(1) + animatedTop) { - if (view instanceof ChatActionCell && messageObject.isDateObject) { - view.setAlpha(0f); - } - continue; - } int position = view.getBottom(); if (position < minPositionHolder) { minPositionHolder = position; @@ -9363,6 +9953,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + currentPinnedMessageId = 0; + if (maxVisibleId == Integer.MIN_VALUE) { + if (startLoadFromMessageId != 0) { + maxVisibleId = startLoadFromMessageId; + } else if (!pinnedMessageIds.isEmpty()) { + maxVisibleId = pinnedMessageIds.get(0) + 1; + } + } + if (!pinnedMessageIds.isEmpty()) { + currentPinnedMessageId = findClosest(pinnedMessageIds, forceNextPinnedMessageId != 0 && (maxVisibleId > forceNextPinnedMessageId || forceScrollToFirst || chatListView.isFastScrollAnimationRunning() || postponedScrollToLastMessageQueryIndex != 0) ? forceNextPinnedMessageId : maxVisibleId, currentPinnedMessageIndex); + if (!loadingPinnedMessagesList && !pinnedEndReached && !pinnedMessageIds.isEmpty() && currentPinnedMessageIndex[0] > pinnedMessageIds.size() - 2) { + getMediaDataController().loadPinnedMessages(dialog_id, pinnedMessageIds.get(pinnedMessageIds.size() - 1), 0); + loadingPinnedMessagesList = true; + } + } getMessagesController().addToPollsQueue(dialog_id, pollsToCheck); if (videoPlayerContainer != null) { if (!foundTextureViewMessage) { @@ -9382,27 +9987,64 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MediaController.getInstance().setCurrentVideoVisible(true); } } - if (minMessageChild != null && (chatListItemAniamtor == null || !chatListItemAniamtor.isRunning())) { + if (minMessageChild != null) { MessageObject messageObject; if (minMessageChild instanceof ChatMessageCell) { messageObject = ((ChatMessageCell) minMessageChild).getMessageObject(); } else { messageObject = ((ChatActionCell) minMessageChild).getMessageObject(); } - floatingDateView.setCustomDate(messageObject.messageOwner.date, inScheduleMode, true); + floatingDateView.setCustomDate(messageObject.messageOwner.date, chatMode == MODE_SCHEDULED, true); } currentFloatingDateOnScreen = false; currentFloatingTopIsNotMessage = !(minChild instanceof ChatMessageCell || minChild instanceof ChatActionCell); if (minDateChild != null) { - if (minDateChild.getTop() > chatListView.getPaddingTop() + animatedTop || currentFloatingTopIsNotMessage) { + boolean showFloatingView = false; + if (minDateChild.getY() > cilpTop || currentFloatingTopIsNotMessage) { if (minDateChild.getAlpha() != 1.0f) { minDateChild.setAlpha(1.0f); } - hideFloatingDateView(!currentFloatingTopIsNotMessage); + if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + messages.size() - 1) { + showFloatingView = false; + if (minDateChild.getAlpha() != 1.0f) { + minDateChild.setAlpha(1.0f); + } + if (floatingDateAnimation != null) { + floatingDateAnimation.cancel(); + floatingDateAnimation = null; + } + floatingDateView.setTag(null); + floatingDateView.setAlpha(0); + currentFloatingDateOnScreen = false; + } else { + hideFloatingDateView(!currentFloatingTopIsNotMessage); + } } else { if (minDateChild.getAlpha() != 0.0f) { minDateChild.setAlpha(0.0f); } + showFloatingView = true; + } + float offset = minDateChild.getY() + minDateChild.getMeasuredHeight() - cilpTop; + if (offset > floatingDateView.getMeasuredHeight() && offset < floatingDateView.getMeasuredHeight() * 2) { + if (chatListView.getChildAdapterPosition(minDateChild) == chatAdapter.messagesStartRow + messages.size() - 1) { + showFloatingView = false; + if (minDateChild.getAlpha() != 1.0f) { + minDateChild.setAlpha(1.0f); + } + if (floatingDateAnimation != null) { + floatingDateAnimation.cancel(); + floatingDateAnimation = null; + } + floatingDateView.setTag(null); + floatingDateView.setAlpha(0); + } else { + floatingDateViewOffset = -floatingDateView.getMeasuredHeight() * 2 + offset; + } + } else { + floatingDateViewOffset = 0; + } + if (showFloatingView) { if (floatingDateAnimation != null) { floatingDateAnimation.cancel(); floatingDateAnimation = null; @@ -9415,21 +10057,57 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } currentFloatingDateOnScreen = true; } - float offset = minDateChild.getBottom() - chatListView.getPaddingTop() - animatedTop; - if (offset > floatingDateView.getMeasuredHeight() && offset < floatingDateView.getMeasuredHeight() * 2) { - floatingDateViewOffset = -floatingDateView.getMeasuredHeight() * 2 + offset; - } else { - floatingDateViewOffset = 0; - } } else { hideFloatingDateView(true); floatingDateViewOffset = 0; } - if (isThreadChat() && previousPinnedMessageVisible != replyMessageVisible) { - updatePinnedMessageView(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150); + if (isThreadChat()) { + if (previousThreadMessageVisible != threadMessageVisible) { + updatePinnedMessageView(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150); + } + } else { + if (currentPinnedMessageId != 0) { + MessageObject object = pinnedMessageObjects.get(currentPinnedMessageId); + if (object == null) { + object = messagesDict[0].get(currentPinnedMessageId); + } + if (object == null) { + if (loadingPinnedMessages.indexOfKey(currentPinnedMessageId) < 0) { + loadingPinnedMessages.put(currentPinnedMessageId, true); + ArrayList ids = new ArrayList<>(); + ids.add(currentPinnedMessageId); + getMediaDataController().loadPinnedMessages(dialog_id, ChatObject.isChannel(currentChat) ? currentChat.id : 0, ids, true); + } + currentPinnedMessageId = previousPinnedMessageId; + } + } else if (previousPinnedMessageId != 0 && !pinnedMessageIds.isEmpty()) { + currentPinnedMessageId = previousPinnedMessageId; + } + if (previousPinnedMessageId != currentPinnedMessageId) { + int animateToNext; + if (previousPinnedMessageId == 0) { + animateToNext = 0; + } else if (previousPinnedMessageId > currentPinnedMessageId) { + animateToNext = 1; + } else { + animateToNext = 2; + } + updatePinnedMessageView(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150, animateToNext); + } else { + updatePinnedListButton(openAnimationStartTime != 0 && SystemClock.elapsedRealtime() >= openAnimationStartTime + 150); + } + } + if (floatingDateView != null) { + float topPanelViewH = Math.max(0, AndroidUtilities.dp(48) + topChatPanelViewOffset); + float pinnedViewH = 0; + if (pinnedMessageView != null && pinnedMessageView.getVisibility() == View.VISIBLE) { + pinnedViewH = Math.max(0, AndroidUtilities.dp(48) + pinnedMessageEnterOffset); + } + int viewsOffset = (int) (contentPaddingTop + topPanelViewH + pinnedViewH); + floatingDateView.setTranslationY(contentPanTranslation + floatingDateViewOffset + viewsOffset + distanceTopViewOffset); } invalidateChatListViewTopPadding(); - if (!firstLoading && !paused && !inPreviewMode && !inScheduleMode && !getMessagesController().ignoreSetOnline) { + if (!firstLoading && !paused && !inPreviewMode && fragmentOpened && chatMode == 0 && !getMessagesController().ignoreSetOnline) { int scheduledRead = 0; if ((maxPositiveUnreadId != Integer.MIN_VALUE || maxNegativeUnreadId != Integer.MAX_VALUE)) { int counterDecrement = 0; @@ -9557,16 +10235,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private int getScrollOffsetForMessage(MessageObject object) { - int offset = Integer.MAX_VALUE; + int exactlyHeight = getHeightForMessage(object); + return Math.max(-AndroidUtilities.dp(2), (chatListView.getMeasuredHeight() - chatListViewPaddingTop - exactlyHeight) / 2); + } + private int getHeightForMessage(MessageObject object) { if (dummyMessageCell == null) { dummyMessageCell = new ChatMessageCell(getParentActivity()); } dummyMessageCell.isChat = currentChat != null || UserObject.isUserSelf(currentUser); dummyMessageCell.isBot = currentUser != null && currentUser.bot; dummyMessageCell.isMegagroup = ChatObject.isChannel(currentChat) && currentChat.megagroup; - int exactlyHeight = dummyMessageCell.computeHeight(object, groupedMessagesMap.get(object.getGroupId())); - return Math.max(-AndroidUtilities.dp(2), offset == Integer.MAX_VALUE ? (chatListView.getMeasuredHeight() - chatListView.getPaddingTop() - exactlyHeight) / 2 : offset); + return dummyMessageCell.computeHeight(object, groupedMessagesMap.get(object.getGroupId())); } private void startMessageUnselect() { @@ -9590,16 +10270,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private AlertDialog progressDialog; + private int nextScrollToMessageId; + private int nextScrollFromMessageId; + private boolean nextScrollSelect; + private int nextScrollLoadIndex; + private boolean nextScrollForce; public void scrollToMessageId(int id, int fromMessageId, boolean select, int loadIndex, boolean forceScroll) { if (id == 0 || chatListView.isFastScrollAnimationRunning() || (chatListItemAniamtor != null && chatListItemAniamtor.isRunning()) || getParentActivity() == null) { + if (id != 0 && getParentActivity() != null) { + nextScrollToMessageId = id; + nextScrollFromMessageId = fromMessageId; + nextScrollSelect = select; + nextScrollLoadIndex = loadIndex; + nextScrollForce = forceScroll; + } return; } + forceNextPinnedMessageId = 0; + forceScrollToFirst = false; wasManualScroll = true; MessageObject object = messagesDict[loadIndex].get(id); boolean query = false; int scrollDirection = RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UNSET; + int scrollFromIndex = 0; if (fromMessageId != 0) { boolean scrollDown = fromMessageId < id; if (isSecretChat()) { @@ -9617,6 +10312,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject.getId() == 0) { continue; } + scrollFromIndex = i - chatAdapter.messagesStartRow; boolean scrollDown = messageObject.getId() < id; if (isSecretChat()) { scrollDown = !scrollDown; @@ -9640,6 +10336,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int index = messages.indexOf(object); if (index != -1) { + if (scrollFromIndex > 0) { + scrollDirection = scrollFromIndex > index ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP; + chatScrollHelper.setScrollDirection(scrollDirection); + } removeSelectedMessageHighlight(); if (select) { highlightMessageId = id; @@ -9671,7 +10371,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (found) { int yOffset = getScrollOffsetForMessage(object); - int scrollY = view.getTop() - chatListView.getPaddingTop() - yOffset; + int scrollY = view.getTop() - chatListViewPaddingTop - yOffset; int maxScrollOffset = chatListView.computeVerticalScrollRange() - chatListView.computeVerticalScrollOffset() - chatListView.computeVerticalScrollExtent(); if (maxScrollOffset < 0) maxScrollOffset = 0; if (scrollY > maxScrollOffset) { @@ -9689,6 +10389,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatScrollHelperCallback.scrollTo = object; chatScrollHelperCallback.lastBottom = false; chatScrollHelperCallback.lastItemOffset = yOffset; + chatScrollHelper.setScrollDirection(scrollDirection); chatScrollHelper.scrollToPosition(position, yOffset, false, true); canShowPagedownButton = true; updatePagedownButtonVisibility(true); @@ -9723,9 +10424,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not postponedScrollIsCanceled = false; waitingForLoad.add(lastLoadIndex); postponedScrollToLastMessageQueryIndex = lastLoadIndex; + postponedScrollMinMessageId = minMessageId[0]; postponedScrollMessageId = id; - getMessagesController().loadMessages(loadIndex == 0 ? dialog_id : mergeDialogId, 0, false, isThreadChat() || AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); - //emptyViewContainer.setVisibility(View.INVISIBLE); + getMessagesController().loadMessages(loadIndex == 0 ? dialog_id : mergeDialogId, 0, false, isThreadChat() || AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } else { View child = chatListView.getChildAt(0); if (child != null && child.getTop() <= 0) { @@ -9938,7 +10639,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (requestCode == 4 && chatAttachAlert != null) { chatAttachAlert.getPhotoLayout().checkStorage(); - } else if (requestCode == 5 && chatAttachAlert != null) { + } else if ((requestCode == 5 || requestCode == 30) && chatAttachAlert != null) { chatAttachAlert.onRequestPermissionsResultFragment(requestCode, permissions, grantResults); } else if ((requestCode == 17 || requestCode == 18) && chatAttachAlert != null) { chatAttachAlert.getPhotoLayout().checkCamera(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED); @@ -10209,14 +10910,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject.canEditMessage(currentChat)) { canEditMessagesCount--; } - if (!messageObject.canDeleteMessage(inScheduleMode, currentChat)) { + if (!messageObject.canDeleteMessage(chatMode == MODE_SCHEDULED, currentChat)) { cantDeleteMessagesCount--; } - if (inScheduleMode || !messageObject.canForwardMessage()) { + if (chatMode == MODE_SCHEDULED || !messageObject.canForwardMessage()) { cantForwardMessagesCount--; } else { canForwardMessagesCount--; } + if (messageObject.isMusic()) { + canSaveMusicCount--; + } else if (messageObject.isDocument()) { + canSaveDocumentsCount--; + } else { + cantSaveMessagesCount--; + } } else { if (selectedMessagesIds[0].size() + selectedMessagesIds[1].size() >= 100) { return; @@ -10231,14 +10939,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messageObject.canEditMessage(currentChat)) { canEditMessagesCount++; } - if (!messageObject.canDeleteMessage(inScheduleMode, currentChat)) { + if (!messageObject.canDeleteMessage(chatMode == MODE_SCHEDULED, currentChat)) { cantDeleteMessagesCount++; } - if (inScheduleMode || !messageObject.canForwardMessage()) { + if (chatMode == MODE_SCHEDULED || !messageObject.canForwardMessage()) { cantForwardMessagesCount++; } else { canForwardMessagesCount++; } + if (messageObject.isMusic()) { + canSaveMusicCount++; + } else if (messageObject.isDocument()) { + canSaveDocumentsCount++; + } else { + cantSaveMessagesCount++; + } if (outside) { showTextSelectionHint(messageObject); } @@ -10254,6 +10969,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not hideActionMode(); updatePinnedMessageView(true); } else { + ActionBarMenuItem saveItem = actionBar.createActionMode().getItem(save_to); ActionBarMenuItem copyItem = actionBar.createActionMode().getItem(copy); ActionBarMenuItem starItem = actionBar.createActionMode().getItem(star); ActionBarMenuItem editItem = actionBar.createActionMode().getItem(edit); @@ -10291,6 +11007,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not forwardButton.setAlpha(cantForwardMessagesCount == 0 ? 1.0f : 0.5f); } } + if (saveItem != null) { + saveItem.setVisibility(((canSaveMusicCount > 0 && canSaveDocumentsCount == 0) || (canSaveMusicCount == 0 && canSaveDocumentsCount > 0)) && cantSaveMessagesCount == 0 ? View.VISIBLE : View.GONE); + saveItem.setContentDescription(canSaveMusicCount > 0 ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + } int copyVisible = copyItem.getVisibility(); int starVisible = starItem.getVisibility(); @@ -10323,7 +11043,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int newVisibility; - if (inScheduleMode || !allowChatActions || selectedCount == 0 || selectedMessagesIds[0].size() != 0 && selectedMessagesIds[1].size() != 0) { + if (chatMode == MODE_SCHEDULED || !allowChatActions || selectedMessagesIds[0].size() != 0 && selectedMessagesIds[1].size() != 0) { newVisibility = View.GONE; } else if (selectedCount == 1) { newVisibility = View.VISIBLE; @@ -10497,12 +11217,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (UserObject.isReplyUser(currentUser)) { avatarContainer.setTitle(LocaleController.getString("RepliesTitle", R.string.RepliesTitle)); - } else if (inScheduleMode) { + } else if (chatMode == MODE_SCHEDULED) { if (UserObject.isUserSelf(currentUser)) { avatarContainer.setTitle(LocaleController.getString("Reminders", R.string.Reminders)); } else { avatarContainer.setTitle(LocaleController.getString("ScheduledMessages", R.string.ScheduledMessages)); } + } else if (chatMode == MODE_PINNED) { + avatarContainer.setTitle(LocaleController.formatPluralString("PinnedMessagesCount", getPinnedMessagesCount())); } else if (currentChat != null) { avatarContainer.setTitle(currentChat.title, currentChat.scam); } else if (currentUser != null) { @@ -10515,6 +11237,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not setParentActivityTitle(avatarContainer.getTitleTextView().getText()); } + private int getPinnedMessagesCount() { + return Math.max(loadedPinnedMessagesCount, totalPinnedMessagesCount); + } + private void updateBotButtons() { if (headerItem == null || currentUser == null || currentEncryptedChat != null || !currentUser.bot) { return; @@ -10550,7 +11276,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateTitleIcons() { - if (avatarContainer == null || inScheduleMode) { + if (avatarContainer == null || chatMode != 0) { return; } Drawable rightIcon = getMessagesController().isDialogMuted(dialog_id) ? Theme.chat_muteIconDrawable : null; @@ -10701,7 +11427,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openVideoEditor(videoPath, null); } } else { - if (editingMessageObject == null && inScheduleMode) { + if (editingMessageObject == null && chatMode == MODE_SCHEDULED) { AlertsCreator.createScheduleDatePickerDialog(getParentActivity(), dialog_id, (notify, scheduleDate) -> { fillEditingMediaWithCaption(null, null); SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), null, uri, dialog_id, replyingMessageObject, getThreadMessage(), null, null, null, null, 0, editingMessageObject, notify, scheduleDate); @@ -10776,28 +11502,36 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not doNotRemoveLoadIndex = false; } if (!doNotRemoveLoadIndex && !openAnimationEnded) { - getNotificationCenter().updateAllowedNotifications(transitionAnimationIndex, new int[]{NotificationCenter.chatInfoDidLoad, NotificationCenter.dialogsNeedReload, NotificationCenter.scheduledMessagesUpdated, - NotificationCenter.closeChats, NotificationCenter.botKeyboardDidLoad, NotificationCenter.userInfoDidLoad, NotificationCenter.needDeleteDialog/*, NotificationCenter.botInfoDidLoad*/}); + int[] alowedNotifications = new int[]{NotificationCenter.chatInfoDidLoad, NotificationCenter.dialogsNeedReload, NotificationCenter.scheduledMessagesUpdated, + NotificationCenter.closeChats, NotificationCenter.botKeyboardDidLoad, NotificationCenter.userInfoDidLoad, NotificationCenter.pinnedInfoDidLoad, NotificationCenter.needDeleteDialog/*, NotificationCenter.botInfoDidLoad*/}; + if (transitionAnimationIndex == 0) { + transitionAnimationIndex = getNotificationCenter().setAnimationInProgress(transitionAnimationIndex, alowedNotifications); + } else { + getNotificationCenter().updateAllowedNotifications(transitionAnimationIndex, alowedNotifications); + } } int index = waitingForLoad.indexOf(queryLoadIndex); int currentUserId = getUserConfig().getClientUserId(); - boolean schedule = (Boolean) args[14]; + int mode = (Integer) args[14]; boolean isCache = (Boolean) args[3]; boolean postponedScroll = postponedScrollToLastMessageQueryIndex > 0 && queryLoadIndex == postponedScrollToLastMessageQueryIndex; + if (postponedScroll) { + postponedScrollToLastMessageQueryIndex = 0; + } if (index == -1) { - if (inScheduleMode && schedule && !isCache) { + if (chatMode == MODE_SCHEDULED && mode == MODE_SCHEDULED && !isCache) { waitingForReplyMessageLoad = true; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } return; } else if (!doNotRemoveLoadIndex) { waitingForLoad.remove(index); } ArrayList messArr = (ArrayList) args[2]; - if (inScheduleMode != schedule) { - if (!inScheduleMode) { + if (chatMode != mode) { + if (chatMode != MODE_SCHEDULED) { scheduledMessagesCount = messArr.size(); updateScheduledInterface(true); } @@ -10806,7 +11540,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean createUnreadLoading = false; boolean showDateAfter = waitingForReplyMessageLoad; if (waitingForReplyMessageLoad) { - if (!inScheduleMode && !createUnreadMessageAfterIdLoading) { + if (chatMode != MODE_SCHEDULED && !createUnreadMessageAfterIdLoading) { boolean found = false; for (int a = 0; a < messArr.size(); a++) { MessageObject obj = messArr.get(a); @@ -10833,7 +11567,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int unreadAfterId = createUnreadMessageAfterId; createUnreadLoading = createUnreadMessageAfterIdLoading; clearChatData(); - if (!inScheduleMode) { + if (chatMode == 0) { createUnreadMessageAfterId = unreadAfterId; startLoadFromMessageId = startLoadFrom; needSelectFromMessageId = needSelect; @@ -10873,7 +11607,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (load_type == 0 && isCache && messArr.size() < count) { postponedScrollToLastMessageQueryIndex = lastLoadIndex; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, count, 0, 0, false, 0, classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, count, 0, 0, false, 0, classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); return; } @@ -10907,7 +11641,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int unreadAfterId = createUnreadMessageAfterId; createUnreadLoading = createUnreadMessageAfterIdLoading; clearChatData(); - if (!inScheduleMode) { + if (chatMode == 0) { createUnreadMessageAfterId = unreadAfterId; startLoadFromMessageId = startLoadFrom; needSelectFromMessageId = needSelect; @@ -10948,7 +11682,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not forwardEndReached[0] = false; minMessageId[0] = 0; } - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { endReached[0] = cacheEndReached[0] = true; forwardEndReached[0] = forwardEndReached[0] = true; } @@ -11021,6 +11755,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not forwardEndReached[0] = true; } } + if (chatMode == MODE_PINNED) { + endReached[loadIndex] = true; + } if (!threadMessageAdded && isThreadChat() && (load_type == 0 && messArr.size() < count || (load_type == 2 || load_type == 3) && endReached[0])) { TLRPC.Message msg = new TLRPC.TL_message(); @@ -11052,7 +11789,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Collections.reverse(messArr); } if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, inScheduleMode, null); + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, null); } int approximateHeightSum = 0; if ((load_type == 2 || load_type == 1) && messArr.isEmpty() && !isCache) { @@ -11089,7 +11826,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentUser.self) { obj.messageOwner.out = true; } - if (!inScheduleMode && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { + if (chatMode != MODE_SCHEDULED && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { obj.setIsRead(); } } @@ -11146,7 +11883,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not continue; } - if (needAnimateToMessage != null && needAnimateToMessage.getId() == messageId && messageId < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && !inScheduleMode) { + if (needAnimateToMessage != null && needAnimateToMessage.getId() == messageId && messageId < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && chatMode != MODE_SCHEDULED) { obj = needAnimateToMessage; animatingMessageObjects.add(obj); needAnimateToMessage = null; @@ -11159,7 +11896,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dayArray = new ArrayList<>(); messagesByDays.put(obj.dateKey, dayArray); TLRPC.Message dateMsg = new TLRPC.TL_message(); - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { if (obj.messageOwner.date == 0x7ffffffe) { dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); } else { @@ -11544,7 +12281,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (first && messages.size() > 0) { first = false; if (isThreadChat()) { - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); } } if (messages.isEmpty() && currentEncryptedChat == null && currentUser != null && currentUser.bot && botUser == null) { @@ -11565,7 +12302,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (newRowsCount == 0 && mergeDialogId != 0 && loadIndex == 0) { getNotificationCenter().updateAllowedNotifications(transitionAnimationIndex, new int[]{NotificationCenter.chatInfoDidLoad, NotificationCenter.dialogsNeedReload, NotificationCenter.scheduledMessagesUpdated, - NotificationCenter.closeChats, NotificationCenter.messagesDidLoad, NotificationCenter.botKeyboardDidLoad, NotificationCenter.userInfoDidLoad, NotificationCenter.needDeleteDialog/*, NotificationCenter.botInfoDidLoad*/}); + NotificationCenter.closeChats, NotificationCenter.messagesDidLoad, NotificationCenter.botKeyboardDidLoad, NotificationCenter.userInfoDidLoad, NotificationCenter.pinnedInfoDidLoad, NotificationCenter.needDeleteDialog/*, NotificationCenter.botInfoDidLoad*/}); } if (showDateAfter) { showFloatingDateView(false); @@ -11597,14 +12334,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (object != null) { int k = messages.indexOf(object); if (k >= 0) { - removeSelectedMessageHighlight(); + int fromPosition = chatLayoutManager.findFirstVisibleItemPosition(); highlightMessageId = object.getId(); + int direction; + if (postponedScrollMinMessageId != 0) { + if (highlightMessageId < 0 && postponedScrollMinMessageId < 0) { + direction = highlightMessageId < postponedScrollMinMessageId ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP; + } else { + direction = highlightMessageId > postponedScrollMinMessageId ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP; + } + } else { + direction = fromPosition > k ? RecyclerAnimationScrollHelper.SCROLL_DIRECTION_DOWN : RecyclerAnimationScrollHelper.SCROLL_DIRECTION_UP; + } + chatScrollHelper.setScrollDirection(direction); + + if (!needSelectFromMessageId) { + removeSelectedMessageHighlight(); + } int yOffset = getScrollOffsetForMessage(object); chatScrollHelperCallback.scrollTo = object; chatScrollHelperCallback.lastBottom = false; chatScrollHelperCallback.lastItemOffset = yOffset; - chatScrollHelper.scrollToPosition(chatAdapter.messagesStartRow + messages.indexOf(object), yOffset, false, true); + chatScrollHelper.scrollToPosition(chatAdapter.messagesStartRow + k, yOffset, false, true); } } } @@ -11620,8 +12372,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (alertTextView != null) { alertTextView.invalidate(); } - if (pinnedMessageTextView != null) { - pinnedMessageTextView.invalidate(); + for (int a = 0; a < 2; a++) { + if (pinnedMessageTextView[a] != null) { + pinnedMessageTextView[a].invalidate(); + } } if (mentionListView != null) { mentionListView.invalidateViews(); @@ -11706,586 +12460,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.didReceiveNewMessages) { long did = (Long) args[0]; + ArrayList arr = (ArrayList) args[1]; if (did == dialog_id) { boolean scheduled = (Boolean) args[2]; - if (scheduled != inScheduleMode) { - if (!inScheduleMode && !isPaused && forwardingMessages == null) { - ArrayList arr = (ArrayList) args[1]; + if (scheduled != (chatMode == MODE_SCHEDULED)) { + if (chatMode != MODE_SCHEDULED && !isPaused && forwardingMessages == null) { if (!arr.isEmpty() && arr.get(0).getId() < 0) { openScheduledMessages(); } } return; } - int currentUserId = getUserConfig().getClientUserId(); - boolean updateChat = false; - boolean hasFromMe = false; - ArrayList arr = (ArrayList) args[1]; - - if (chatListItemAniamtor != null) { - chatListItemAniamtor.setShouldAnimateEnterFromBottom(true); - } - - boolean notifiedSearch = false; - LongSparseArray scheduledGroupReplacement = null; - for (int a = 0; a < arr.size(); a++) { - MessageObject messageObject = arr.get(a); - int messageId = messageObject.getId(); - if (threadMessageId != 0) { - if (messageId > 0 && messageId <= (messageObject.isOut() ? threadMaxOutboxReadId : threadMaxInboxReadId)) { - messageObject.setIsRead(); - } - } - if (messageObject.isDice()) { - messageObject.wasUnread = true; - } - if (inScheduleMode && messageObject.hasValidGroupId() && messagesDict[0].indexOfKey(messageObject.getId()) >= 0) { - long groupId = messageObject.getGroupId(); - if (scheduledGroupReplacement == null) { - scheduledGroupReplacement = new LongSparseArray<>(); - } - Long localId = scheduledGroupReplacement.get(groupId); - if (localId == null) { - localId = Utilities.random.nextLong(); - scheduledGroupReplacement.put(groupId, localId); - } - messageObject.localGroupId = localId; - } - if (messageObject.isOut()) { - if (!notifiedSearch) { - notifiedSearch = true; - NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); - } - if (currentChat != null && currentChat.slowmode_enabled && messageObject.isSent() && !inScheduleMode) { - if (chatInfo != null) { - int date = messageObject.messageOwner.date + chatInfo.slowmode_seconds; - int currentTime = getConnectionsManager().getCurrentTime(); - if (date > getConnectionsManager().getCurrentTime()) { - chatInfo.slowmode_next_send_date = Math.max(chatInfo.slowmode_next_send_date, Math.min(currentTime + chatInfo.slowmode_seconds, date)); - if (chatActivityEnterView != null) { - chatActivityEnterView.setSlowModeTimer(chatInfo.slowmode_next_send_date); - } - } - } - getMessagesController().loadFullChat(currentChat.id, 0, true); - } - } - if (currentChat != null) { - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser && messageObject.messageOwner.action.user_id == currentUserId || - messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser && messageObject.messageOwner.action.users.contains(currentUserId)) { - TLRPC.Chat newChat = getMessagesController().getChat(currentChat.id); - if (newChat != null) { - currentChat = newChat; - checkActionBarMenu(); - updateBottomOverlay(); - if (avatarContainer != null) { - avatarContainer.updateSubtitle(true); - } - } - } - } else if (inlineReturn != 0) { - if (messageObject.messageOwner.reply_markup != null) { - for (int b = 0; b < messageObject.messageOwner.reply_markup.rows.size(); b++) { - TLRPC.TL_keyboardButtonRow row = messageObject.messageOwner.reply_markup.rows.get(b); - for (int c = 0; c < row.buttons.size(); c++) { - TLRPC.KeyboardButton button = row.buttons.get(c); - if (button instanceof TLRPC.TL_keyboardButtonSwitchInline) { - processSwitchButton((TLRPC.TL_keyboardButtonSwitchInline) button); - break; - } - } - } - } - } - if (messageObject.getReplyMsgId() != 0 && messageObject.replyMessageObject == null) { - messageObject.replyMessageObject = messagesDict[0].get(messageObject.getReplyMsgId()); - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { - messageObject.generatePinMessageText(null, null); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { - messageObject.generateGameMessageText(null); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) { - messageObject.generatePaymentSentMessageText(null); - } - if (messageObject.isMegagroup() && messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageOwner != null) { - messageObject.replyMessageObject.messageOwner.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; - } - } - } - - if (inScheduleMode && !arr.isEmpty()) { - replaceMessageObjects(arr, 0, true); - } - - boolean needMoveScrollToLastMessage = false; - - boolean reloadMegagroup = false; - if (!forwardEndReached[0]) { - int currentMaxDate = Integer.MIN_VALUE; - int currentMinMsgId = Integer.MIN_VALUE; - if (currentEncryptedChat != null) { - currentMinMsgId = Integer.MAX_VALUE; - } - - for (int a = 0; a < arr.size(); a++) { - MessageObject obj = arr.get(a); - if (threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { - continue; - } - int messageId = obj.getId(); - - if (obj.isOut() && waitingForSendingMessageLoad) { - waitingForSendingMessageLoad = false; - chatActivityEnterView.hideTopView(true); - if (changeBoundAnimator != null) { - changeBoundAnimator.start(); - } - } - - if (!inScheduleMode && currentUser != null && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { - obj.setIsRead(); - } - TLRPC.MessageAction action = obj.messageOwner.action; - if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) action.encryptedAction).ttl_seconds); - } - if (action instanceof TLRPC.TL_messageActionChatMigrateTo) { - migrateToNewChat(obj); - return; - } else if (currentChat != null && currentChat.megagroup && (action instanceof TLRPC.TL_messageActionChatAddUser || action instanceof TLRPC.TL_messageActionChatDeleteUser)) { - reloadMegagroup = true; - } - if (a == 0 && obj.messageOwner.id < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && !inScheduleMode) { - needAnimateToMessage = obj; - } - if (obj.isOut() && obj.wasJustSent) { - scrollToLastMessage(); - return; - } - if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { - continue; - } - if (currentChat != null && currentChat.creator && (!ChatObject.isChannel(currentChat) || currentChat.megagroup) && (action instanceof TLRPC.TL_messageActionChatCreate || action instanceof TLRPC.TL_messageActionChatEditPhoto && messages.size() < 2)) { - continue; - } - if (action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { - continue; - } - if (threadMessageId != 0 && obj.messageOwner instanceof TLRPC.TL_messageEmpty) { - continue; - } - if (threadMessageObject != null && obj.isReply()) { - int mid = obj.getReplyAnyMsgId(); - if (threadMessageObject.getId() == mid) { - threadMessageObject.messageOwner.replies.replies++; - } - } - addToPolls(obj, null); - obj.checkLayout(); - currentMaxDate = Math.max(currentMaxDate, obj.messageOwner.date); - if (messageId > 0) { - currentMinMsgId = Math.max(messageId, currentMinMsgId); - last_message_id = Math.max(last_message_id, messageId); - } else if (currentEncryptedChat != null) { - currentMinMsgId = Math.min(messageId, currentMinMsgId); - last_message_id = Math.min(last_message_id, messageId); - } - - if (threadMessageId == 0) { - if (obj.messageOwner.mentioned && obj.isContentUnread()) { - newMentionsCount++; - } - newUnreadMessageCount++; - } - if (obj.type == 10 || obj.type == 11) { - updateChat = true; - } - } - if (newUnreadMessageCount != 0 && pagedownButtonCounter != null) { - pagedownButtonCounter.setVisibility(View.VISIBLE); - if (prevSetUnreadCount != newUnreadMessageCount) { - prevSetUnreadCount = newUnreadMessageCount; - pagedownButtonCounter.setText(String.format("%d", newUnreadMessageCount)); - } - } - if (newMentionsCount != 0 && mentiondownButtonCounter != null) { - mentiondownButtonCounter.setVisibility(View.VISIBLE); - mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); - showMentionDownButton(true, true); - } - - updateVisibleRows(); - } else { - LongSparseArray newGroups = null; - HashMap> webpagesToReload = null; - if (BuildVars.LOGS_ENABLED) { - FileLog.d("received new messages " + arr.size() + " in dialog " + dialog_id); - } - for (int a = 0; a < arr.size(); a++) { - MessageObject obj = arr.get(a); - if (obj.scheduled != inScheduleMode || threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { - continue; - } - int placeToPaste = -1; - int messageId = obj.getId(); - if (inScheduleMode && messagesDict[0].indexOfKey(messageId) >= 0) { - MessageObject removed = messagesDict[0].get(messageId); - messagesDict[0].remove(messageId); - if (removed != null) { - int index = messages.indexOf(removed); - messages.remove(index); - ArrayList dayArr = messagesByDays.get(removed.dateKey); - dayArr.remove(removed); - if (dayArr.isEmpty()) { - messagesByDays.remove(removed.dateKey); - if (index >= 0 && index < messages.size()) { - messages.remove(index); - } - } - if (removed.hasValidGroupId()) { - MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(removed.getGroupId()); - groupedMessages.messages.remove(removed); - if (newGroups == null) { - newGroups = new LongSparseArray<>(); - } - newGroups.put(groupedMessages.groupId, groupedMessages); - } - if (chatAdapter != null) { - chatAdapter.notifyDataSetChanged(false); - } - } - } - if (isSecretChat()) { - checkSecretMessageForLocation(obj); - } - if (!inScheduleMode && currentUser != null && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { - obj.setIsRead(); - } - TLRPC.MessageAction action = obj.messageOwner.action; - if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { - avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) action.encryptedAction).ttl_seconds); - } - if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { - continue; - } - if (currentChat != null && currentChat.creator && (!ChatObject.isChannel(currentChat) || currentChat.megagroup) && (action instanceof TLRPC.TL_messageActionChatCreate || action instanceof TLRPC.TL_messageActionChatEditPhoto && messages.size() < 2)) { - continue; - } - if (action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { - continue; - } - if (threadMessageId != 0 && obj.messageOwner instanceof TLRPC.TL_messageEmpty) { - continue; - } - if (threadMessageObject != null && threadMessageObject.messageOwner.replies != null && obj.isReply()) { - int mid = obj.getReplyAnyMsgId(); - if (threadMessageObject.getId() == mid) { - threadMessageObject.messageOwner.replies.replies++; - } - } - addToPolls(obj, null); - if (a == 0 && obj.messageOwner.id < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && !inScheduleMode) { - animatingMessageObjects.add(obj); - } - - MessageObject.GroupedMessages groupedMessages; - if (obj.hasValidGroupId()) { - groupedMessages = groupedMessagesMap.get(obj.getGroupId()); - if (groupedMessages == null) { - groupedMessages = new MessageObject.GroupedMessages(); - groupedMessages.groupId = obj.getGroupId(); - groupedMessagesMap.put(groupedMessages.groupId, groupedMessages); - } - if (newGroups == null) { - newGroups = new LongSparseArray<>(); - } - newGroups.put(groupedMessages.groupId, groupedMessages); - groupedMessages.messages.add(obj); - } else { - groupedMessages = null; - } - - if (groupedMessages != null) { - int size = groupedMessages.messages.size(); - MessageObject messageObject = size > 1 ? groupedMessages.messages.get(groupedMessages.messages.size() - 2) : null; - if (messageObject != null) { - placeToPaste = messages.indexOf(messageObject); - } - } - - if (placeToPaste == -1) { - if (!obj.scheduled && obj.messageOwner.id < 0 || messages.isEmpty()) { - placeToPaste = 0; - } else { - int size = messages.size(); - for (int b = 0; b < size; b++) { - MessageObject lastMessage = messages.get(b); - if (lastMessage.type >= 0 && lastMessage.messageOwner.date > 0) { - if (!inScheduleMode && lastMessage.messageOwner.id > 0 && obj.messageOwner.id > 0 && lastMessage.messageOwner.id < obj.messageOwner.id || lastMessage.messageOwner.date <= obj.messageOwner.date) { - MessageObject.GroupedMessages lastGroupedMessages; - if (lastMessage.getGroupId() != 0) { - lastGroupedMessages = groupedMessagesMap.get(lastMessage.getGroupId()); - if (lastGroupedMessages != null && lastGroupedMessages.messages.size() == 0) { - lastGroupedMessages = null; - } - } else { - lastGroupedMessages = null; - } - if (lastGroupedMessages == null) { - placeToPaste = b; - } else { - placeToPaste = messages.indexOf(lastGroupedMessages.messages.get(lastGroupedMessages.messages.size() - 1)); - } - break; - } - } - } - if (placeToPaste == -1 || placeToPaste > messages.size()) { - placeToPaste = messages.size(); - } - } - } - 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 (action instanceof TLRPC.TL_messageActionChatMigrateTo) { - migrateToNewChat(obj); - if (newGroups != null) { - for (int b = 0; b < newGroups.size(); b++) { - newGroups.valueAt(b).calculate(); - } - } - return; - } else if (currentChat != null && currentChat.megagroup && (action instanceof TLRPC.TL_messageActionChatAddUser || action instanceof TLRPC.TL_messageActionChatDeleteUser)) { - reloadMegagroup = true; - } - if (minDate[0] == 0 || obj.messageOwner.date < minDate[0]) { - minDate[0] = obj.messageOwner.date; - } - - if (obj.isOut() && !obj.messageOwner.from_scheduled) { - removeUnreadPlane(true); - hideDistanceView(); - hasFromMe = true; - } - - if (messageId > 0) { - maxMessageId[0] = Math.min(messageId, maxMessageId[0]); - minMessageId[0] = Math.max(messageId, minMessageId[0]); - } else if (currentEncryptedChat != null) { - maxMessageId[0] = Math.max(messageId, maxMessageId[0]); - minMessageId[0] = Math.min(messageId, minMessageId[0]); - } - maxDate[0] = Math.max(maxDate[0], obj.messageOwner.date); - messagesDict[0].put(messageId, obj); - ArrayList dayArray = messagesByDays.get(obj.dateKey); - if (placeToPaste > messages.size()) { - placeToPaste = messages.size(); - } - if (dayArray == null) { - dayArray = new ArrayList<>(); - messagesByDays.put(obj.dateKey, dayArray); - TLRPC.Message dateMsg = new TLRPC.TL_message(); - if (inScheduleMode) { - if (obj.messageOwner.date == 0x7ffffffe) { - dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); - } else { - dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); - } - } else { - dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); - } - dateMsg.id = 0; - Calendar calendar = JalaliCalendar.mInstance(); - calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.MINUTE, 0); - dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); - MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); - dateObj.type = 10; - dateObj.contentType = 1; - dateObj.isDateObject = true; - dateObj.stableId = lastStableId++; - messages.add(placeToPaste, dateObj); - if (chatAdapter != null) { - chatAdapter.notifyItemInserted(placeToPaste); - } - } - if (!obj.isOut() || obj.messageOwner.from_scheduled) { - if (paused && placeToPaste == 0) { - if (!scrollToTopUnReadOnResume && unreadMessageObject != null) { - removeMessageObject(unreadMessageObject); - if (placeToPaste > 0) { - placeToPaste--; - } - unreadMessageObject = null; - } - if (unreadMessageObject == null) { - TLRPC.Message dateMsg = new TLRPC.TL_message(); - dateMsg.message = ""; - dateMsg.id = 0; - MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); - dateObj.type = 6; - dateObj.contentType = 2; - dateObj.stableId = lastStableId++; - messages.add(0, dateObj); - if (chatAdapter != null) { - chatAdapter.notifyItemInserted(0); - } - unreadMessageObject = dateObj; - scrollToMessage = unreadMessageObject; - scrollToMessagePosition = -10000; - scrollToTopUnReadOnResume = true; - } - } - } - - dayArray.add(0, obj); - - if (chatAdapter != null && placeToPaste >= 0 && placeToPaste < messages.size()) { - MessageObject prevMessage = messages.get(placeToPaste); - if (prevMessage.hasValidGroupId() && prevMessage.getGroupId() != obj.getGroupId()) { - MessageObject.GroupedMessages group = groupedMessagesMap.get(prevMessage.getGroupId()); - if (group != null && group.messages.size() > 1) { - int size = group.messages.size(); - chatAdapter.notifyItemRangeChanged(1, size - 1); - } - } - } - obj.stableId = lastStableId++; - messages.add(placeToPaste, obj); - if (placeToPaste == 0) { - needMoveScrollToLastMessage = true; - } - if (chatAdapter != null) { - chatAdapter.notifyItemChanged(placeToPaste); - chatAdapter.notifyItemInserted(placeToPaste); - } - if (obj.isOut() && waitingForSendingMessageLoad) { - waitingForSendingMessageLoad = false; - chatActivityEnterView.hideTopView(true); - if (changeBoundAnimator != null) { - changeBoundAnimator.start(); - } - } - if (threadMessageId == 0) { - if (!obj.isOut() && obj.messageOwner.mentioned && obj.isContentUnread()) { - newMentionsCount++; - } - newUnreadMessageCount++; - } - if (obj.type == 10 || obj.type == 11) { - updateChat = true; - } - } - if (webpagesToReload != null) { - getMessagesController().reloadWebPages(dialog_id, webpagesToReload, inScheduleMode); - } - if (newGroups != null) { - for (int a = 0; a < newGroups.size(); a++) { - MessageObject.GroupedMessages groupedMessages = newGroups.valueAt(a); - int oldCount = groupedMessages.posArray.size(); - groupedMessages.calculate(); - int newCount = groupedMessages.posArray.size(); - if (newCount - oldCount > 0 && chatAdapter != null) { - int index = messages.indexOf(groupedMessages.messages.get(groupedMessages.messages.size() - 1)); - if (index >= 0) { - chatAdapter.notifyItemRangeChanged(index, newCount); - } - } - } - } - - showProgressView(false); - if (chatAdapter == null) { - scrollToTopOnResume = true; - } - - if (chatListView != null && chatAdapter != null) { - int lastVisible = chatLayoutManager.findFirstVisibleItemPosition(); - if (lastVisible == RecyclerView.NO_POSITION) { - lastVisible = 0; - } - View child = chatLayoutManager.findViewByPosition(lastVisible); - int diff; - if (child != null) { - diff = child.getBottom() - chatListView.getMeasuredHeight(); - } else { - diff = 0; - } - if (lastVisible == 0 && diff <= AndroidUtilities.dp(5) || hasFromMe) { - newUnreadMessageCount = 0; - if (!firstLoading && !inScheduleMode) { - if (paused) { - scrollToTopOnResume = true; - } else { - forceScrollToTop = true; - moveScrollToLastMessage(); - } - } - } else { - if (newUnreadMessageCount != 0 && pagedownButtonCounter != null) { - pagedownButtonCounter.setVisibility(View.VISIBLE); - if (prevSetUnreadCount != newUnreadMessageCount) { - prevSetUnreadCount = newUnreadMessageCount; - pagedownButtonCounter.setText(String.format("%d", newUnreadMessageCount)); - } - } - canShowPagedownButton = true; - updatePagedownButtonVisibility(true); - } - if (newMentionsCount != 0 && mentiondownButtonCounter != null) { - mentiondownButtonCounter.setVisibility(View.VISIBLE); - mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); - showMentionDownButton(true, true); - } - } else { - scrollToTopOnResume = true; - } - } - if (inScheduleMode && !arr.isEmpty()) { - MessageObject messageObject = arr.get(0); - int mid = messageObject.getId(); - if (mid < 0) { - if (chatListItemAniamtor != null) { - chatListItemAniamtor.setShouldAnimateEnterFromBottom(needMoveScrollToLastMessage); - } - if (needMoveScrollToLastMessage) { - moveScrollToLastMessage(); - } else { - int index = messages.indexOf(messageObject); - if (chatLayoutManager != null && index > 0 && (chatLayoutManager.findViewByPosition(chatAdapter.messagesStartRow + index) != null || chatLayoutManager.findViewByPosition(chatAdapter.messagesStartRow + index - 1) != null)) { - chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + messages.indexOf(messageObject), getScrollOffsetForMessage(messageObject), false); - } else { - AndroidUtilities.runOnUIThread(() -> scrollToMessageId(mid, 0, false, 0, true)); - } - } - - } - } - if (!messages.isEmpty() && botUser != null && botUser.length() == 0) { - botUser = null; - updateBottomOverlay(); - } - if (updateChat) { - updateTitle(); - checkAndUpdateAvatar(); - } - if (reloadMegagroup) { - getMessagesController().loadFullChat(currentChat.id, 0, true); - } - checkWaitingForReplies(); - updateReplyMessageHeader(true); + processNewMessages(arr); } else if (ChatObject.isChannel(currentChat) && !currentChat.megagroup && chatInfo != null && did == -chatInfo.linked_chat_id) { - ArrayList arr = (ArrayList) args[1]; for (int a = 0, N = arr.size(); a < N; a++) { MessageObject messageObject = arr.get(a); if (messageObject.isReply()) { @@ -12369,7 +12556,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } int inbox = (Integer) args[2]; int outbox = (Integer) args[3]; - boolean updated = false; if (inbox > threadMaxInboxReadId) { threadMaxInboxReadId = inbox; for (int a = 0, size2 = messages.size(); a < size2; a++) { @@ -12380,7 +12566,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } obj.setIsRead(); - updated = true; + if (chatAdapter != null) { + chatAdapter.invalidateRowWithMessageObject(obj); + } } } } @@ -12394,15 +12582,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } obj.setIsRead(); - updated = true; + if (chatAdapter != null) { + chatAdapter.updateRowWithMessageObject(obj, false); + } } } } - if (updated) { - updateVisibleRows(); - } } else if (id == NotificationCenter.messagesRead) { - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { return; } SparseLongArray inbox = (SparseLongArray) args[0]; @@ -12422,6 +12609,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } obj.setIsRead(); + if (chatAdapter != null) { + chatAdapter.invalidateRowWithMessageObject(obj); + } updated = true; newUnreadMessageCount--; } @@ -12460,44 +12650,37 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0, size2 = messages.size(); a < size2; a++) { MessageObject obj = messages.get(a); if (obj.isOut() && obj.getId() > 0 && obj.getId() <= messageId) { - if (!obj.isUnread()) { - break; - } obj.setIsRead(); - updated = true; + if (chatAdapter != null) { + chatAdapter.invalidateRowWithMessageObject(obj); + } } } break; } } - if (updated) { - updateVisibleRows(); - } } else if (id == NotificationCenter.historyCleared) { long did = (Long) args[0]; if (did != dialog_id) { return; } int max_id = (Integer) args[1]; - boolean updated = false; + if (!pinnedMessageIds.isEmpty()) { + pinnedMessageIds.clear(); + pinnedMessageObjects.clear(); + currentPinnedMessageId = 0; + loadedPinnedMessagesCount = 0; + totalPinnedMessagesCount = 0; + updatePinnedMessageView(true); + } + boolean updated = false; for (int b = 0; b < messages.size(); b++) { MessageObject obj = messages.get(b); int mid = obj.getId(); if (mid <= 0 || mid > max_id) { continue; } - if (chatInfo != null && chatInfo.pinned_msg_id == mid) { - pinnedMessageObject = null; - chatInfo.pinned_msg_id = 0; - getMessagesStorage().updateChatPinnedMessage(chatInfo.id, 0); - updatePinnedMessageView(true); - } else if (userInfo != null && userInfo.pinned_msg_id == mid) { - pinnedMessageObject = null; - userInfo.pinned_msg_id = 0; - getMessagesStorage().updateUserPinnedMessage(chatInfo.id, 0); - updatePinnedMessageView(true); - } messages.remove(b); b--; messagesDict[0].remove(mid); @@ -12531,7 +12714,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not maxDate[0] = maxDate[1] = Integer.MIN_VALUE; minDate[0] = minDate[1] = 0; waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); loading = true; } else { if (botButtons != null) { @@ -12555,230 +12738,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.messagesDeleted) { boolean scheduled = (Boolean) args[2]; - if (scheduled != inScheduleMode) { + if (scheduled != (chatMode == MODE_SCHEDULED)) { return; } ArrayList markAsDeletedMessages = (ArrayList) args[0]; - ArrayList removedIndexes = new ArrayList<>(); - int channelId = (Integer) args[1]; - int loadIndex = 0; - if (ChatObject.isChannel(currentChat)) { - if (channelId == 0 && mergeDialogId != 0) { - loadIndex = 1; - } else if (channelId == currentChat.id) { - loadIndex = 0; - } else { - return; - } - } else if (channelId != 0) { - return; - } - boolean updated = false; - LongSparseArray newGroups = null; - LongSparseArray newGroupsSizes = null; - int size = markAsDeletedMessages.size(); - boolean updatedSelected = false; - boolean updatedSelectedLast = false; - boolean updateScheduled = false; - boolean hasChatInBack = false; - boolean updatedReplies = false; - - if (threadMessageObject != null && parentLayout != null) { - for (int a = 0, N = parentLayout.fragmentsStack.size() - 1; a < N; a++) { - BaseFragment fragment = parentLayout.fragmentsStack.get(a); - if (fragment != this && fragment instanceof ChatActivity) { - ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.inScheduleMode == inScheduleMode) { - hasChatInBack = true; - break; - } - } - } - } - - int commentsDeleted = 0; - for (int a = 0; a < size; a++) { - Integer ids = markAsDeletedMessages.get(a); - MessageObject obj = messagesDict[loadIndex].get(ids); - if (loadIndex == 0 && (chatInfo != null && chatInfo.pinned_msg_id == ids || userInfo != null && userInfo.pinned_msg_id == ids)) { - pinnedMessageObject = null; - if (chatInfo != null) { - chatInfo.pinned_msg_id = 0; - } else if (userInfo != null) { - userInfo.pinned_msg_id = 0; - } - getMessagesStorage().updateChatPinnedMessage(channelId, 0); - updatePinnedMessageView(true); - } - if (obj != null) { - if (obj.messageOwner.reply_to != null) { - int replyId = obj.getReplyAnyMsgId(); - if (threadMessageObject != null && threadMessageObject.getId() == replyId) { - if (!hasChatInBack && threadMessageObject.hasReplies()) { - threadMessageObject.messageOwner.replies.replies--; - } - if (replyOriginalMessageId != 0) { - commentsDeleted++; - } - updatedReplies = true; - } else { - MessageObject replyObject = messagesDict[loadIndex].get(replyId); - if (replyObject != null && replyObject.hasReplies()) { - replyObject.messageOwner.replies.replies--; - replyObject.viewsReloaded = false; - } - } - } - obj.deleted = true; - if (editingMessageObject == obj) { - hideFieldPanel(true); - } - int index = messages.indexOf(obj); - if (index != -1) { - if (obj.scheduled) { - scheduledMessagesCount--; - updateScheduled = true; - } - if (selectedMessagesIds[loadIndex].indexOfKey(ids) >= 0) { - updatedSelected = true; - addToSelectedMessages(obj, false, updatedSelectedLast = (a == size - 1)); - } - MessageObject removed = messages.remove(index); - if (chatAdapter != null) { - removedIndexes.add(chatAdapter.messagesStartRow + index); - } - if (removed.getGroupId() != 0) { - MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(removed.getGroupId()); - if (groupedMessages != null) { - if (newGroups == null) { - newGroups = new LongSparseArray<>(); - newGroupsSizes = new LongSparseArray<>(); - } - newGroups.put(groupedMessages.groupId, groupedMessages); - if (newGroupsSizes.get(groupedMessages.groupId) == null) { - newGroupsSizes.put(groupedMessages.groupId, groupedMessages.messages.size()); - } - groupedMessages.messages.remove(obj); - } - } - messagesDict[loadIndex].remove(ids); - ArrayList dayArr = messagesByDays.get(obj.dateKey); - if (dayArr != null) { - dayArr.remove(obj); - if (dayArr.isEmpty()) { - messagesByDays.remove(obj.dateKey); - if (index >= 0 && index < messages.size()) { - messages.remove(index); - if (chatAdapter != null) { - removedIndexes.add(chatAdapter.messagesStartRow + index); - } - } - } - } - updated = true; - } - } - } - if (updatedReplies) { - updateReplyMessageHeader(true); - } - if (commentsDeleted != 0) { - getNotificationCenter().postNotificationName(NotificationCenter.changeRepliesCounter, replyOriginalChat.id, replyOriginalMessageId, -commentsDeleted); - getMessagesStorage().updateRepliesCount(replyOriginalChat.id, replyOriginalMessageId, null, 0, -commentsDeleted); - } - if (updatedSelected) { - if (!updatedSelectedLast) { - addToSelectedMessages(null, false, true); - } - updateActionModeTitle(); - } - if (newGroups != null) { - for (int a = 0; a < newGroups.size(); a++) { - MessageObject.GroupedMessages groupedMessages = newGroups.valueAt(a); - if (chatListItemAniamtor != null) { - if (groupedMessages.messages.size() == 1) { - chatListItemAniamtor.groupWillTransformToSingleMessage(groupedMessages); - } else { - chatListItemAniamtor.groupWillChanged(groupedMessages); - } - } - - if (groupedMessages.messages.isEmpty()) { - groupedMessagesMap.remove(groupedMessages.groupId); - } else { - groupedMessages.calculate(); - MessageObject messageObject = groupedMessages.messages.get(groupedMessages.messages.size() - 1); - int index = messages.indexOf(messageObject); - if (index >= 0) { - if (chatAdapter != null) { - chatAdapter.notifyItemRangeChanged(index + chatAdapter.messagesStartRow, newGroupsSizes.get(groupedMessages.groupId)); - } - } - } - } - } - if (messages.isEmpty()) { - if (!endReached[0] && !loading) { - showProgressView(false); - if (chatListView != null) { - chatListView.setEmptyView(null); - } - if (currentEncryptedChat == null) { - maxMessageId[0] = maxMessageId[1] = Integer.MAX_VALUE; - minMessageId[0] = minMessageId[1] = Integer.MIN_VALUE; - } else { - maxMessageId[0] = maxMessageId[1] = Integer.MIN_VALUE; - minMessageId[0] = minMessageId[1] = Integer.MAX_VALUE; - } - maxDate[0] = maxDate[1] = Integer.MIN_VALUE; - minDate[0] = minDate[1] = 0; - waitingForLoad.add(lastLoadIndex); - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); - loading = true; - } else { - if (botButtons != null) { - botButtons = null; - if (chatActivityEnterView != null) { - chatActivityEnterView.setButtons(null, false); - } - } - if (currentEncryptedChat == null && currentUser != null && currentUser.bot && botUser == null) { - botUser = ""; - updateBottomOverlay(); - } - } - canShowPagedownButton = false; - updatePagedownButtonVisibility(true); - showMentionDownButton(false, true); - } - if (updated) { - if (chatAdapter != null) { - for (int a = 0, N = removedIndexes.size(); a < N; a++) { - chatAdapter.notifyItemRemoved(removedIndexes.get(a)); - } - if (!isThreadChat() || messages.size() <= 3) { - removeUnreadPlane(false); - } - chatAdapter.notifyItemRangeChanged(chatAdapter.messagesStartRow, messages.size()); - } - updateVisibleRows(); - } else if (threadMessageId == 0) { - first_unread_id = 0; - last_message_id = 0; - createUnreadMessageAfterId = 0; - removeMessageObject(unreadMessageObject); - unreadMessageObject = null; - if (pagedownButtonCounter != null) { - pagedownButtonCounter.setVisibility(View.INVISIBLE); - } - } - if (updateScheduled) { - updateScheduledInterface(true); - } + processDeletedMessages(markAsDeletedMessages, channelId); } else if (id == NotificationCenter.messageReceivedByServer) { Boolean scheduled = (Boolean) args[6]; - if (scheduled != inScheduleMode) { + if (scheduled != (chatMode == MODE_SCHEDULED)) { return; } Integer msgId = (Integer) args[0]; @@ -12862,10 +12830,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ArrayList messArr = new ArrayList<>(); messArr.add(obj); if (currentEncryptedChat == null) { - getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, inScheduleMode, null); + getMediaDataController().loadReplyMessagesForMessages(messArr, dialog_id, chatMode == MODE_SCHEDULED, null); } if (chatAdapter != null) { - chatAdapter.updateRowWithMessageObject(obj, true); + chatAdapter.updateRowWithMessageObject(obj, false); } if (chatLayoutManager != null) { if (mediaUpdated && chatLayoutManager.findFirstVisibleItemPosition() == 0) { @@ -12880,7 +12848,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (obj != null) { obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; if (chatAdapter != null) { - chatAdapter.updateRowWithMessageObject(obj, true); + chatAdapter.updateRowWithMessageObject(obj, false); } } } else if (id == NotificationCenter.messageSendError) { @@ -12930,16 +12898,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionsAdapter.setChatInfo(chatInfo); } if (!isThreadChat()) { - if (args[3] instanceof MessageObject) { - pinnedMessageObject = (MessageObject) args[3]; - updatePinnedMessageView(false); - } else { - updatePinnedMessageView(true); - } if (avatarContainer != null) { avatarContainer.updateOnlineCount(); avatarContainer.updateSubtitle(); } + if (!loadingPinnedMessagesList && !pinnedMessageIds.isEmpty() && chatInfo.pinned_msg_id > pinnedMessageIds.get(0)) { + getMediaDataController().loadPinnedMessages(dialog_id, 0, chatInfo.pinned_msg_id); + loadingPinnedMessagesList = true; + } } if (chatInfo instanceof TLRPC.TL_chatFull) { hasBotsCommands = false; @@ -12987,7 +12953,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (mentionsAdapter != null) { mentionsAdapter.setBotsCount(botsCount); } - if (!inScheduleMode && ChatObject.isChannel(currentChat) && mergeDialogId == 0 && chatInfo.migrated_from_chat_id != 0 && !isThreadChat()) { + if (chatMode == 0 && ChatObject.isChannel(currentChat) && mergeDialogId == 0 && chatInfo.migrated_from_chat_id != 0 && !isThreadChat()) { mergeDialogId = -chatInfo.migrated_from_chat_id; maxMessageId[1] = chatInfo.migrated_from_max_id; if (chatAdapter != null) { @@ -13061,9 +13027,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (obj.messageOwner.date - 1 <= date) { obj.setIsRead(); + if (chatAdapter != null) { + chatAdapter.invalidateRowWithMessageObject(obj); + } } } - updateVisibleRows(); } } else if (id == NotificationCenter.removeAllMessagesFromDialog) { long did = (Long) args[0]; @@ -13436,12 +13404,131 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checkWaitingForReplies(); } updateReplyMessageHeader(true); - } else if (id == NotificationCenter.pinnedMessageDidLoad) { - MessageObject message = (MessageObject) args[0]; - if (message.getDialogId() == dialog_id && (chatInfo != null && chatInfo.pinned_msg_id == message.getId() || userInfo != null && userInfo.pinned_msg_id == message.getId())) { - pinnedMessageObject = message; - loadingPinnedMessage = 0; - updatePinnedMessageView(true); + } else if (id == NotificationCenter.didLoadPinnedMessages) { + long did = (Long) args[0]; + if (did == dialog_id) { + ArrayList ids = (ArrayList) args[1]; + boolean pin = (Boolean) args[2]; + ArrayList arrayList = (ArrayList) args[3]; + HashMap dict = null; + if (ids != null) { + HashMap replaceObjects = (HashMap) args[4]; + int maxId = (Integer) args[5]; + int totalPinnedCount = (Integer) args[6]; + boolean endReached = (Boolean) args[7]; + HashMap oldPinned = new HashMap<>(pinnedMessageObjects); + if (replaceObjects != null) { + loadingPinnedMessagesList = false; + if (maxId == 0) { + pinnedMessageIds.clear(); + pinnedMessageObjects.clear(); + } + totalPinnedMessagesCount = totalPinnedCount; + pinnedEndReached = endReached; + } + boolean updated = false; + if (arrayList != null) { + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, null); + } + for (int a = 0, N = ids.size(); a < N; a++) { + Integer mid = ids.get(a); + if (pin) { + if (pinnedMessageObjects.containsKey(mid)) { + continue; + } + pinnedMessageIds.add(mid); + MessageObject object = oldPinned.get(mid); + if (object == null) { + object = messagesDict[0].get(mid); + } + if (object == null && arrayList != null) { + if (dict == null) { + dict = new HashMap<>(); + for (int b = 0, N2 = arrayList.size(); b < N2; b++) { + MessageObject obj = arrayList.get(b); + if (obj != null) { + dict.put(obj.getId(), obj); + } + } + } + object = dict.get(mid); + } + if (object == null && replaceObjects != null) { + object = replaceObjects.get(mid); + } + pinnedMessageObjects.put(mid, object); + if (replaceObjects == null) { + totalPinnedMessagesCount++; + } + } else { + if (!pinnedMessageObjects.containsKey(mid)) { + continue; + } + pinnedMessageObjects.remove(mid); + pinnedMessageIds.remove(mid); + if (replaceObjects == null) { + totalPinnedMessagesCount--; + } + } + loadedPinnedMessagesCount = pinnedMessageIds.size(); + if (chatAdapter != null) { + MessageObject obj = messagesDict[0].get(mid); + if (obj != null) { + if (obj.hasValidGroupId()) { + MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(obj.getGroupId()); + if (groupedMessages != null) { + int index = messages.indexOf(groupedMessages.messages.get(groupedMessages.messages.size() - 1)); + if (index >= 0) { + chatAdapter.notifyItemRangeChanged(index, groupedMessages.messages.size()); + } + } + } else { + chatAdapter.updateRowWithMessageObject(obj, false); + } + } + } + updated = true; + } + if (updated) { + if (chatMode == MODE_PINNED && avatarContainer != null) { + avatarContainer.setTitle(LocaleController.formatPluralString("PinnedMessagesCount", getPinnedMessagesCount())); + } + Collections.sort(pinnedMessageIds, (o1, o2) -> o2.compareTo(o1)); + if (pinnedMessageIds.isEmpty()) { + hidePinnedMessageView(true); + } else { + updateMessagesVisiblePart(false); + } + } + if (chatMode == MODE_PINNED) { + if (pin) { + if (arrayList != null) { + processNewMessages(arrayList); + } + } else { + processDeletedMessages(ids, ChatObject.isChannel(currentChat) ? currentChat.id : 0); + } + } + } else { + if (pin) { + for (int a = 0, N = arrayList.size(); a < N; a++) { + MessageObject message = arrayList.get(a); + if (pinnedMessageObjects.containsKey(message.getId())) { + pinnedMessageObjects.put(message.getId(), message); + } + loadingPinnedMessages.remove(message.getId()); + } + getMediaDataController().loadReplyMessagesForMessages(arrayList, dialog_id, false, null); + updateMessagesVisiblePart(false); + } else { + pinnedMessageIds.clear(); + pinnedMessageObjects.clear(); + currentPinnedMessageId = 0; + loadedPinnedMessagesCount = 0; + totalPinnedMessagesCount = 0; + hidePinnedMessageView(true); + } + } } } else if (id == NotificationCenter.didReceivedWebpages) { ArrayList arrayList = (ArrayList) args[0]; @@ -13479,7 +13566,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.messagesReadContent) { ArrayList arrayList = (ArrayList) args[0]; - boolean updated = false; int currentChannelId = ChatObject.isChannel(currentChat) ? currentChat.id : 0; for (int a = 0; a < arrayList.size(); a++) { long mid = arrayList.get(a); @@ -13493,7 +13579,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject currentMessage = messagesDict[0].get((int) mid); if (currentMessage != null) { currentMessage.setContentIsRead(); - updated = true; if (currentMessage.messageOwner.mentioned) { newMentionsCount--; if (newMentionsCount <= 0) { @@ -13506,11 +13591,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + if (chatAdapter != null) { + chatAdapter.invalidateRowWithMessageObject(currentMessage); + } } } - if (updated) { - updateVisibleRows(); - } } else if (id == NotificationCenter.botInfoDidLoad) { int guid = (Integer) args[1]; if (classGuid == guid) { @@ -13627,7 +13712,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not newGroups.put(groupedMessages.groupId, groupedMessages); } } - updated = true; + if (chatAdapter != null) { + chatAdapter.updateRowWithMessageObject(messageObject, false); + } } } } @@ -13641,7 +13728,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not BaseFragment fragment = parentLayout.fragmentsStack.get(a); if (fragment != this && fragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.inScheduleMode == inScheduleMode) { + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode()) { hasChatInBack = true; break; } @@ -13685,6 +13772,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not newGroups = new LongSparseArray<>(); } newGroups.put(groupedMessages.groupId, groupedMessages); + for (int b = 0, N2 = groupedMessages.messages.size(); b < N2; b++) { + groupedMessages.messages.get(b).animateComments = true; + } } } else if (chatAdapter != null) { int row = messages.indexOf(messageObject); @@ -13694,6 +13784,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } updatedRows.add(row + chatAdapter.messagesStartRow); } + messageObject.animateComments = true; } updated = true; } @@ -13732,6 +13823,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (did == dialog_id) { applyDraftMaybe(true); } + } else if (id == NotificationCenter.pinnedInfoDidLoad) { + long did = (Long) args[0]; + if (did == dialog_id) { + ArrayList pinnedMessages = (ArrayList) args[1]; + if (chatMode == MODE_PINNED) { + pinnedMessageIds = new ArrayList<>(pinnedMessages); + pinnedMessageObjects = new HashMap<>((HashMap) args[2]); + } else { + pinnedMessageIds = pinnedMessages; + pinnedMessageObjects = (HashMap) args[2]; + } + + loadedPinnedMessagesCount = pinnedMessageIds.size(); + totalPinnedMessagesCount = (Integer) args[3]; + pinnedEndReached = (Boolean) args[4]; + + getMediaDataController().loadReplyMessagesForMessages(new ArrayList<>(pinnedMessageObjects.values()), dialog_id, false, null); + + if (!loadingPinnedMessagesList && totalPinnedMessagesCount == 0 && !pinnedEndReached) { + getMediaDataController().loadPinnedMessages(dialog_id, 0, pinnedMessageIds.isEmpty() ? 0 : pinnedMessageIds.get(0)); + loadingPinnedMessagesList = true; + } + } } else if (id == NotificationCenter.userInfoDidLoad) { Integer uid = (Integer) args[0]; if (currentUser != null && currentUser.id == uid) { @@ -13749,11 +13863,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not headerItem.hideSubItem(video_call); } } - if (args[2] instanceof MessageObject) { - pinnedMessageObject = (MessageObject) args[2]; - updatePinnedMessageView(false); - } else { - updatePinnedMessageView(true); + if (!loadingPinnedMessagesList && !pinnedMessageIds.isEmpty() && userInfo.pinned_msg_id > pinnedMessageIds.get(0)) { + getMediaDataController().loadPinnedMessages(dialog_id, 0, userInfo.pinned_msg_id); + loadingPinnedMessagesList = true; } } } else if (id == NotificationCenter.didSetNewWallpapper) { @@ -13912,10 +14024,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not idsToRemove = new ArrayList<>(); } idsToRemove.add(waitingForReplies.keyAt(a)); - if (object.replyMessageObject.messageOwner.fwd_from != null && MessageObject.getPeerId(object.replyMessageObject.messageOwner.fwd_from.saved_from_peer) == dialog_id && object.replyMessageObject.messageOwner.fwd_from.channel_post != 0) { + if (!(object.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) && object.replyMessageObject.messageOwner.fwd_from != null && MessageObject.getPeerId(object.replyMessageObject.messageOwner.fwd_from.saved_from_peer) == dialog_id && object.replyMessageObject.messageOwner.fwd_from.channel_post != 0) { MessageObject obj = messagesDict[0].get(object.replyMessageObject.messageOwner.fwd_from.channel_post); if (obj != null && obj.messageOwner.replies != null) { obj.messageOwner.replies.replies += 1; + obj.animateComments = true; TLRPC.Peer peer = object.messageOwner.from_id; if (peer == null) { peer = object.messageOwner.peer_id; @@ -13939,6 +14052,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not newGroups = new LongSparseArray<>(); } newGroups.put(groupedMessages.groupId, groupedMessages); + for (int b = 0, N2 = groupedMessages.messages.size(); b < N2; b++) { + groupedMessages.messages.get(b).animateComments = true; + } } } else { int row = messages.indexOf(obj); @@ -14026,9 +14142,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (startLoadFromMessageIdSaved != 0) { startLoadFromMessageId = startLoadFromMessageIdSaved; startLoadFromMessageIdSaved = 0; - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, 0, true, 0, classGuid, 3, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } else { - getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), inScheduleMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, AndroidUtilities.isTablet() ? 30 : 20, 0, 0, true, 0, classGuid, 2, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); } } else { if (progressView != null) { @@ -14067,7 +14183,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (lower_part != 0) { if (lower_part > 0) { bundle.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { bundle.putInt("chat_id", -lower_part); } } else { @@ -14080,14 +14196,823 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } + private void processNewMessages(ArrayList arr) { + int currentUserId = getUserConfig().getClientUserId(); + boolean updateChat = false; + boolean hasFromMe = false; + + + if (chatListItemAniamtor != null) { + chatListItemAniamtor.setShouldAnimateEnterFromBottom(true); + } + + boolean notifiedSearch = false; + LongSparseArray scheduledGroupReplacement = null; + for (int a = 0; a < arr.size(); a++) { + MessageObject messageObject = arr.get(a); + int messageId = messageObject.getId(); + if (threadMessageId != 0) { + if (messageId > 0 && messageId <= (messageObject.isOut() ? threadMaxOutboxReadId : threadMaxInboxReadId)) { + messageObject.setIsRead(); + } + } + if (messageObject.isDice() && !messageObject.isForwarded()) { + messageObject.wasUnread = true; + } + if (chatMode == MODE_SCHEDULED && messageObject.hasValidGroupId() && messagesDict[0].indexOfKey(messageObject.getId()) >= 0) { + long groupId = messageObject.getGroupId(); + if (scheduledGroupReplacement == null) { + scheduledGroupReplacement = new LongSparseArray<>(); + } + Long localId = scheduledGroupReplacement.get(groupId); + if (localId == null) { + localId = Utilities.random.nextLong(); + scheduledGroupReplacement.put(groupId, localId); + } + messageObject.localGroupId = localId; + } + if (messageObject.isOut()) { + if (!notifiedSearch) { + notifiedSearch = true; + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.closeSearchByActiveAction); + } + if (currentChat != null && currentChat.slowmode_enabled && messageObject.isSent() && chatMode != MODE_SCHEDULED) { + if (chatInfo != null) { + int date = messageObject.messageOwner.date + chatInfo.slowmode_seconds; + int currentTime = getConnectionsManager().getCurrentTime(); + if (date > getConnectionsManager().getCurrentTime()) { + chatInfo.slowmode_next_send_date = Math.max(chatInfo.slowmode_next_send_date, Math.min(currentTime + chatInfo.slowmode_seconds, date)); + if (chatActivityEnterView != null) { + chatActivityEnterView.setSlowModeTimer(chatInfo.slowmode_next_send_date); + } + } + } + getMessagesController().loadFullChat(currentChat.id, 0, true); + } + } + if (currentChat != null) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser && messageObject.messageOwner.action.user_id == currentUserId || + messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser && messageObject.messageOwner.action.users.contains(currentUserId)) { + TLRPC.Chat newChat = getMessagesController().getChat(currentChat.id); + if (newChat != null) { + currentChat = newChat; + checkActionBarMenu(); + updateBottomOverlay(); + if (avatarContainer != null) { + avatarContainer.updateSubtitle(true); + } + } + } + } else if (inlineReturn != 0) { + if (messageObject.messageOwner.reply_markup != null) { + for (int b = 0; b < messageObject.messageOwner.reply_markup.rows.size(); b++) { + TLRPC.TL_keyboardButtonRow row = messageObject.messageOwner.reply_markup.rows.get(b); + for (int c = 0; c < row.buttons.size(); c++) { + TLRPC.KeyboardButton button = row.buttons.get(c); + if (button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + processSwitchButton((TLRPC.TL_keyboardButtonSwitchInline) button); + break; + } + } + } + } + } + if (messageObject.getReplyMsgId() != 0 && messageObject.replyMessageObject == null) { + messageObject.replyMessageObject = messagesDict[0].get(messageObject.getReplyMsgId()); + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + messageObject.generatePinMessageText(null, null); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionGameScore) { + messageObject.generateGameMessageText(null); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPaymentSent) { + messageObject.generatePaymentSentMessageText(null); + } + if (messageObject.isMegagroup() && messageObject.replyMessageObject != null && messageObject.replyMessageObject.messageOwner != null) { + messageObject.replyMessageObject.messageOwner.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + } + + if (chatMode == MODE_SCHEDULED && !arr.isEmpty()) { + replaceMessageObjects(arr, 0, true); + } + + boolean needMoveScrollToLastMessage = false; + + boolean reloadMegagroup = false; + if (!forwardEndReached[0]) { + int currentMaxDate = Integer.MIN_VALUE; + int currentMinMsgId = Integer.MIN_VALUE; + if (currentEncryptedChat != null) { + currentMinMsgId = Integer.MAX_VALUE; + } + + for (int a = 0; a < arr.size(); a++) { + MessageObject obj = arr.get(a); + if (threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { + continue; + } + int messageId = obj.getId(); + + if (obj.isOut() && waitingForSendingMessageLoad) { + waitingForSendingMessageLoad = false; + chatActivityEnterView.hideTopView(true); + if (changeBoundAnimator != null) { + changeBoundAnimator.start(); + } + } + + if (chatMode != MODE_SCHEDULED && currentUser != null && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { + obj.setIsRead(); + } + TLRPC.MessageAction action = obj.messageOwner.action; + if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) action.encryptedAction).ttl_seconds); + } + if (action instanceof TLRPC.TL_messageActionChatMigrateTo) { + migrateToNewChat(obj); + return; + } else if (currentChat != null && currentChat.megagroup && (action instanceof TLRPC.TL_messageActionChatAddUser || action instanceof TLRPC.TL_messageActionChatDeleteUser)) { + reloadMegagroup = true; + } + if (a == 0 && obj.messageOwner.id < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && chatMode != MODE_SCHEDULED) { + needAnimateToMessage = obj; + } + if (obj.isOut() && obj.wasJustSent) { + scrollToLastMessage(); + return; + } + if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { + continue; + } + if (currentChat != null && currentChat.creator && (!ChatObject.isChannel(currentChat) || currentChat.megagroup) && (action instanceof TLRPC.TL_messageActionChatCreate || action instanceof TLRPC.TL_messageActionChatEditPhoto && messages.size() < 2)) { + continue; + } + if (action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { + continue; + } + if (threadMessageId != 0 && obj.messageOwner instanceof TLRPC.TL_messageEmpty) { + continue; + } + if (threadMessageObject != null && obj.isReply() && !(obj.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage)) { + int mid = obj.getReplyAnyMsgId(); + if (threadMessageObject.getId() == mid) { + threadMessageObject.messageOwner.replies.replies++; + } + } + addToPolls(obj, null); + obj.checkLayout(); + currentMaxDate = Math.max(currentMaxDate, obj.messageOwner.date); + if (messageId > 0) { + currentMinMsgId = Math.max(messageId, currentMinMsgId); + last_message_id = Math.max(last_message_id, messageId); + } else if (currentEncryptedChat != null) { + currentMinMsgId = Math.min(messageId, currentMinMsgId); + last_message_id = Math.min(last_message_id, messageId); + } + + if (threadMessageId == 0) { + if (obj.messageOwner.mentioned && obj.isContentUnread()) { + newMentionsCount++; + } + newUnreadMessageCount++; + } + if (obj.type == 10 || obj.type == 11) { + updateChat = true; + } + } + if (newUnreadMessageCount != 0 && pagedownButtonCounter != null) { + pagedownButtonCounter.setVisibility(View.VISIBLE); + if (prevSetUnreadCount != newUnreadMessageCount) { + prevSetUnreadCount = newUnreadMessageCount; + pagedownButtonCounter.setText(String.format("%d", newUnreadMessageCount)); + } + } + if (newMentionsCount != 0 && mentiondownButtonCounter != null) { + mentiondownButtonCounter.setVisibility(View.VISIBLE); + mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); + showMentionDownButton(true, true); + } + + updateVisibleRows(); + } else { + LongSparseArray newGroups = null; + HashMap> webpagesToReload = null; + if (BuildVars.LOGS_ENABLED) { + FileLog.d("received new messages " + arr.size() + " in dialog " + dialog_id); + } + for (int a = 0; a < arr.size(); a++) { + MessageObject obj = arr.get(a); + if (obj.scheduled != (chatMode == MODE_SCHEDULED) || threadMessageId != 0 && threadMessageId != obj.getReplyTopMsgId() && threadMessageId != obj.getReplyMsgId()) { + continue; + } + int placeToPaste = -1; + int messageId = obj.getId(); + if (chatMode == MODE_SCHEDULED && messagesDict[0].indexOfKey(messageId) >= 0) { + MessageObject removed = messagesDict[0].get(messageId); + messagesDict[0].remove(messageId); + if (removed != null) { + int index = messages.indexOf(removed); + messages.remove(index); + ArrayList dayArr = messagesByDays.get(removed.dateKey); + dayArr.remove(removed); + if (dayArr.isEmpty()) { + messagesByDays.remove(removed.dateKey); + if (index >= 0 && index < messages.size()) { + messages.remove(index); + } + } + if (removed.hasValidGroupId()) { + MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(removed.getGroupId()); + groupedMessages.messages.remove(removed); + if (newGroups == null) { + newGroups = new LongSparseArray<>(); + } + newGroups.put(groupedMessages.groupId, groupedMessages); + } + if (chatAdapter != null) { + chatAdapter.notifyDataSetChanged(false); + } + } + } + if (isSecretChat()) { + checkSecretMessageForLocation(obj); + } + if (chatMode != MODE_SCHEDULED && currentUser != null && (currentUser.bot && obj.isOut() || currentUser.id == currentUserId)) { + obj.setIsRead(); + } + TLRPC.MessageAction action = obj.messageOwner.action; + if (avatarContainer != null && currentEncryptedChat != null && action instanceof TLRPC.TL_messageEncryptedAction && action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) action.encryptedAction).ttl_seconds); + } + if (obj.type < 0 || messagesDict[0].indexOfKey(messageId) >= 0) { + continue; + } + if (currentChat != null && currentChat.creator && (!ChatObject.isChannel(currentChat) || currentChat.megagroup) && (action instanceof TLRPC.TL_messageActionChatCreate || action instanceof TLRPC.TL_messageActionChatEditPhoto && messages.size() < 2)) { + continue; + } + if (action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { + continue; + } + if (threadMessageId != 0 && obj.messageOwner instanceof TLRPC.TL_messageEmpty) { + continue; + } + if (threadMessageObject != null && threadMessageObject.messageOwner.replies != null && obj.isReply() && !(obj.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage)) { + int mid = obj.getReplyAnyMsgId(); + if (threadMessageObject.getId() == mid) { + threadMessageObject.messageOwner.replies.replies++; + } + } + addToPolls(obj, null); + if (a == 0 && obj.messageOwner.id < 0 && obj.type == MessageObject.TYPE_ROUND_VIDEO && chatMode != MODE_SCHEDULED) { + animatingMessageObjects.add(obj); + } + + MessageObject.GroupedMessages groupedMessages; + if (obj.hasValidGroupId()) { + groupedMessages = groupedMessagesMap.get(obj.getGroupId()); + if (groupedMessages == null) { + groupedMessages = new MessageObject.GroupedMessages(); + groupedMessages.groupId = obj.getGroupId(); + groupedMessagesMap.put(groupedMessages.groupId, groupedMessages); + } + if (newGroups == null) { + newGroups = new LongSparseArray<>(); + } + newGroups.put(groupedMessages.groupId, groupedMessages); + groupedMessages.messages.add(obj); + } else { + groupedMessages = null; + } + + if (groupedMessages != null) { + int size = groupedMessages.messages.size(); + MessageObject messageObject = size > 1 ? groupedMessages.messages.get(groupedMessages.messages.size() - 2) : null; + if (messageObject != null) { + placeToPaste = messages.indexOf(messageObject); + } + } + + if (placeToPaste == -1) { + if (!obj.scheduled && obj.messageOwner.id < 0 || messages.isEmpty()) { + placeToPaste = 0; + } else { + int size = messages.size(); + for (int b = 0; b < size; b++) { + MessageObject lastMessage = messages.get(b); + if (lastMessage.type >= 0 && lastMessage.messageOwner.date > 0) { + if (chatMode != MODE_SCHEDULED && lastMessage.messageOwner.id > 0 && obj.messageOwner.id > 0 && lastMessage.messageOwner.id < obj.messageOwner.id || lastMessage.messageOwner.date <= obj.messageOwner.date) { + MessageObject.GroupedMessages lastGroupedMessages; + if (lastMessage.getGroupId() != 0) { + lastGroupedMessages = groupedMessagesMap.get(lastMessage.getGroupId()); + if (lastGroupedMessages != null && lastGroupedMessages.messages.size() == 0) { + lastGroupedMessages = null; + } + } else { + lastGroupedMessages = null; + } + if (lastGroupedMessages == null) { + placeToPaste = b; + } else { + placeToPaste = messages.indexOf(lastGroupedMessages.messages.get(lastGroupedMessages.messages.size() - 1)); + } + break; + } + } + } + if (placeToPaste == -1 || placeToPaste > messages.size()) { + placeToPaste = messages.size(); + } + } + } + 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 (action instanceof TLRPC.TL_messageActionChatMigrateTo) { + migrateToNewChat(obj); + if (newGroups != null) { + for (int b = 0; b < newGroups.size(); b++) { + newGroups.valueAt(b).calculate(); + } + } + return; + } else if (currentChat != null && currentChat.megagroup && (action instanceof TLRPC.TL_messageActionChatAddUser || action instanceof TLRPC.TL_messageActionChatDeleteUser)) { + reloadMegagroup = true; + } + if (minDate[0] == 0 || obj.messageOwner.date < minDate[0]) { + minDate[0] = obj.messageOwner.date; + } + + if (obj.isOut() && !obj.messageOwner.from_scheduled) { + removeUnreadPlane(true); + hideDistanceView(); + hasFromMe = true; + } + + if (messageId > 0) { + maxMessageId[0] = Math.min(messageId, maxMessageId[0]); + minMessageId[0] = Math.max(messageId, minMessageId[0]); + } else if (currentEncryptedChat != null) { + maxMessageId[0] = Math.max(messageId, maxMessageId[0]); + minMessageId[0] = Math.min(messageId, minMessageId[0]); + } + maxDate[0] = Math.max(maxDate[0], obj.messageOwner.date); + messagesDict[0].put(messageId, obj); + ArrayList dayArray = messagesByDays.get(obj.dateKey); + if (placeToPaste > messages.size()) { + placeToPaste = messages.size(); + } + if (dayArray == null) { + dayArray = new ArrayList<>(); + messagesByDays.put(obj.dateKey, dayArray); + TLRPC.Message dateMsg = new TLRPC.TL_message(); + if (chatMode == MODE_SCHEDULED) { + if (obj.messageOwner.date == 0x7ffffffe) { + dateMsg.message = LocaleController.getString("MessageScheduledUntilOnline", R.string.MessageScheduledUntilOnline); + } else { + dateMsg.message = LocaleController.formatString("MessageScheduledOn", R.string.MessageScheduledOn, LocaleController.formatDateChat(obj.messageOwner.date, true)); + } + } else { + dateMsg.message = LocaleController.formatDateChat(obj.messageOwner.date); + } + dateMsg.id = 0; + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(((long) obj.messageOwner.date) * 1000); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + dateMsg.date = (int) (calendar.getTimeInMillis() / 1000); + MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); + dateObj.type = 10; + dateObj.contentType = 1; + dateObj.isDateObject = true; + dateObj.stableId = lastStableId++; + messages.add(placeToPaste, dateObj); + if (chatAdapter != null) { + chatAdapter.notifyItemInserted(placeToPaste); + } + } + if (!(obj.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (!obj.isOut() || obj.messageOwner.from_scheduled)) { + if (paused && placeToPaste == 0) { + if (!scrollToTopUnReadOnResume && unreadMessageObject != null) { + removeMessageObject(unreadMessageObject); + unreadMessageObject = null; + } + if (unreadMessageObject == null) { + TLRPC.Message dateMsg = new TLRPC.TL_message(); + dateMsg.message = ""; + dateMsg.id = 0; + MessageObject dateObj = new MessageObject(currentAccount, dateMsg, false, false); + dateObj.type = 6; + dateObj.contentType = 2; + dateObj.stableId = lastStableId++; + messages.add(0, dateObj); + if (chatAdapter != null) { + chatAdapter.notifyItemInserted(0); + } + unreadMessageObject = dateObj; + scrollToMessage = unreadMessageObject; + scrollToMessagePosition = -10000; + scrollToTopUnReadOnResume = true; + } + } + } + + dayArray.add(0, obj); + + if (chatAdapter != null && placeToPaste >= 0 && placeToPaste < messages.size()) { + MessageObject prevMessage = messages.get(placeToPaste); + if (prevMessage.hasValidGroupId() && prevMessage.getGroupId() != obj.getGroupId()) { + MessageObject.GroupedMessages group = groupedMessagesMap.get(prevMessage.getGroupId()); + if (group != null && group.messages.size() > 1) { + int size = group.messages.size(); + chatAdapter.notifyItemRangeChanged(1, size - 1); + } + } + } + obj.stableId = lastStableId++; + messages.add(placeToPaste, obj); + if (placeToPaste == 0) { + needMoveScrollToLastMessage = true; + } + if (chatAdapter != null) { + chatAdapter.notifyItemChanged(placeToPaste); + chatAdapter.notifyItemInserted(placeToPaste); + } + if (obj.isOut() && waitingForSendingMessageLoad) { + waitingForSendingMessageLoad = false; + chatActivityEnterView.hideTopView(true); + if (changeBoundAnimator != null) { + changeBoundAnimator.start(); + } + } + if (threadMessageId == 0) { + if (!obj.isOut() && obj.messageOwner.mentioned && obj.isContentUnread()) { + newMentionsCount++; + } + newUnreadMessageCount++; + } + if (obj.type == 10 || obj.type == 11) { + updateChat = true; + } + } + if (webpagesToReload != null) { + getMessagesController().reloadWebPages(dialog_id, webpagesToReload, chatMode == MODE_SCHEDULED); + } + if (newGroups != null) { + for (int a = 0; a < newGroups.size(); a++) { + MessageObject.GroupedMessages groupedMessages = newGroups.valueAt(a); + int oldCount = groupedMessages.posArray.size(); + groupedMessages.calculate(); + int newCount = groupedMessages.posArray.size(); + if (newCount - oldCount > 0 && chatAdapter != null) { + int index = messages.indexOf(groupedMessages.messages.get(groupedMessages.messages.size() - 1)); + if (index >= 0) { + chatAdapter.notifyItemRangeChanged(index, newCount); + } + } + } + } + + showProgressView(false); + if (chatAdapter == null) { + scrollToTopOnResume = true; + } + + if (chatListView != null && chatAdapter != null) { + int lastVisible = chatLayoutManager.findFirstVisibleItemPosition(); + if (lastVisible == RecyclerView.NO_POSITION) { + lastVisible = 0; + } + View child = chatLayoutManager.findViewByPosition(lastVisible); + int diff; + if (child != null) { + diff = child.getBottom() - chatListView.getMeasuredHeight(); + } else { + diff = 0; + } + if (lastVisible == 0 && diff <= AndroidUtilities.dp(5) || hasFromMe) { + newUnreadMessageCount = 0; + if (!firstLoading && chatMode != MODE_SCHEDULED) { + if (paused) { + scrollToTopOnResume = true; + } else { + forceScrollToTop = true; + moveScrollToLastMessage(); + } + } + } else { + if (newUnreadMessageCount != 0 && pagedownButtonCounter != null) { + pagedownButtonCounter.setVisibility(View.VISIBLE); + if (prevSetUnreadCount != newUnreadMessageCount) { + prevSetUnreadCount = newUnreadMessageCount; + pagedownButtonCounter.setText(String.format("%d", newUnreadMessageCount)); + } + } + canShowPagedownButton = true; + updatePagedownButtonVisibility(true); + } + if (newMentionsCount != 0 && mentiondownButtonCounter != null) { + mentiondownButtonCounter.setVisibility(View.VISIBLE); + mentiondownButtonCounter.setText(String.format("%d", newMentionsCount)); + showMentionDownButton(true, true); + } + } else { + scrollToTopOnResume = true; + } + } + if (chatMode == MODE_SCHEDULED && !arr.isEmpty()) { + MessageObject messageObject = arr.get(0); + int mid = messageObject.getId(); + if (mid < 0) { + if (chatListItemAniamtor != null) { + chatListItemAniamtor.setShouldAnimateEnterFromBottom(needMoveScrollToLastMessage); + } + if (needMoveScrollToLastMessage) { + moveScrollToLastMessage(); + } else { + int index = messages.indexOf(messageObject); + if (chatLayoutManager != null && index > 0 && (chatLayoutManager.findViewByPosition(chatAdapter.messagesStartRow + index) != null || chatLayoutManager.findViewByPosition(chatAdapter.messagesStartRow + index - 1) != null)) { + chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + messages.indexOf(messageObject), getScrollOffsetForMessage(messageObject), false); + } else { + AndroidUtilities.runOnUIThread(() -> scrollToMessageId(mid, 0, false, 0, true)); + } + } + + } + } + if (!messages.isEmpty() && botUser != null && botUser.length() == 0) { + botUser = null; + updateBottomOverlay(); + } + if (updateChat) { + updateTitle(); + checkAndUpdateAvatar(); + } + if (reloadMegagroup) { + getMessagesController().loadFullChat(currentChat.id, 0, true); + } + checkWaitingForReplies(); + updateReplyMessageHeader(true); + } + + private void processDeletedMessages(ArrayList markAsDeletedMessages, int channelId) { + ArrayList removedIndexes = new ArrayList<>(); + int loadIndex = 0; + if (ChatObject.isChannel(currentChat)) { + if (channelId == 0 && mergeDialogId != 0) { + loadIndex = 1; + } else if (channelId == currentChat.id) { + loadIndex = 0; + } else { + return; + } + } else if (channelId != 0) { + return; + } + boolean updated = false; + LongSparseArray newGroups = null; + LongSparseArray newGroupsSizes = null; + int size = markAsDeletedMessages.size(); + boolean updatedSelected = false; + boolean updatedSelectedLast = false; + boolean updateScheduled = false; + boolean hasChatInBack = false; + boolean updatedReplies = false; + + if (threadMessageObject != null && parentLayout != null) { + for (int a = 0, N = parentLayout.fragmentsStack.size() - 1; a < N; a++) { + BaseFragment fragment = parentLayout.fragmentsStack.get(a); + if (fragment != this && fragment instanceof ChatActivity) { + ChatActivity chatActivity = (ChatActivity) fragment; + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode()) { + hasChatInBack = true; + break; + } + } + } + } + + int commentsDeleted = 0; + for (int a = 0; a < size; a++) { + Integer mid = markAsDeletedMessages.get(a); + MessageObject obj = messagesDict[loadIndex].get(mid); + if (loadIndex == 0 && pinnedMessageObjects.containsKey(mid)) { + pinnedMessageObjects.remove(mid); + pinnedMessageIds.remove(mid); + loadedPinnedMessagesCount = pinnedMessageIds.size(); + totalPinnedMessagesCount--; + if (totalPinnedMessagesCount < 0) { + totalPinnedMessagesCount = 0; + } + if (currentPinnedMessageId == mid) { + currentPinnedMessageId = 0; + } + } + if (obj != null) { + if (obj.messageOwner.reply_to != null && !(obj.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage)) { + int replyId = obj.getReplyAnyMsgId(); + if (threadMessageObject != null && threadMessageObject.getId() == replyId) { + if (!hasChatInBack && threadMessageObject.hasReplies()) { + threadMessageObject.messageOwner.replies.replies--; + } + if (replyOriginalMessageId != 0) { + commentsDeleted++; + } + updatedReplies = true; + } else { + MessageObject replyObject = messagesDict[loadIndex].get(replyId); + if (replyObject != null && replyObject.hasReplies()) { + replyObject.messageOwner.replies.replies--; + replyObject.viewsReloaded = false; + } + } + } + obj.deleted = true; + if (editingMessageObject == obj) { + hideFieldPanel(true); + } + int index = messages.indexOf(obj); + if (index != -1) { + if (obj.scheduled) { + scheduledMessagesCount--; + updateScheduled = true; + } + if (selectedMessagesIds[loadIndex].indexOfKey(mid) >= 0) { + updatedSelected = true; + addToSelectedMessages(obj, false, updatedSelectedLast = (a == size - 1)); + } + MessageObject removed = messages.remove(index); + if (chatAdapter != null) { + removedIndexes.add(chatAdapter.messagesStartRow + index); + } + if (removed.getGroupId() != 0) { + MessageObject.GroupedMessages groupedMessages = groupedMessagesMap.get(removed.getGroupId()); + if (groupedMessages != null) { + if (newGroups == null) { + newGroups = new LongSparseArray<>(); + newGroupsSizes = new LongSparseArray<>(); + } + newGroups.put(groupedMessages.groupId, groupedMessages); + if (newGroupsSizes.get(groupedMessages.groupId) == null) { + newGroupsSizes.put(groupedMessages.groupId, groupedMessages.messages.size()); + } + groupedMessages.messages.remove(obj); + } + } + messagesDict[loadIndex].remove(mid); + ArrayList dayArr = messagesByDays.get(obj.dateKey); + if (dayArr != null) { + dayArr.remove(obj); + if (dayArr.isEmpty()) { + messagesByDays.remove(obj.dateKey); + if (index >= 0 && index < messages.size()) { + messages.remove(index); + if (chatAdapter != null) { + removedIndexes.add(chatAdapter.messagesStartRow + index); + } + } + } + } + updated = true; + } + } + } + if (updatedReplies) { + updateReplyMessageHeader(true); + } + if (commentsDeleted != 0) { + getNotificationCenter().postNotificationName(NotificationCenter.changeRepliesCounter, replyOriginalChat.id, replyOriginalMessageId, -commentsDeleted); + getMessagesStorage().updateRepliesCount(replyOriginalChat.id, replyOriginalMessageId, null, 0, -commentsDeleted); + } + if (updatedSelected) { + if (!updatedSelectedLast) { + addToSelectedMessages(null, false, true); + } + updateActionModeTitle(); + } + if (newGroups != null) { + for (int a = 0; a < newGroups.size(); a++) { + MessageObject.GroupedMessages groupedMessages = newGroups.valueAt(a); + if (chatListItemAniamtor != null) { + if (groupedMessages.messages.size() == 1) { + chatListItemAniamtor.groupWillTransformToSingleMessage(groupedMessages); + } else { + chatListItemAniamtor.groupWillChanged(groupedMessages); + } + } + + if (groupedMessages.messages.isEmpty()) { + groupedMessagesMap.remove(groupedMessages.groupId); + } else { + groupedMessages.calculate(); + MessageObject messageObject = groupedMessages.messages.get(groupedMessages.messages.size() - 1); + int index = messages.indexOf(messageObject); + if (index >= 0) { + if (chatAdapter != null) { + chatAdapter.notifyItemRangeChanged(index + chatAdapter.messagesStartRow, newGroupsSizes.get(groupedMessages.groupId)); + } + } + } + } + } + if (messages.isEmpty()) { + if (!endReached[0] && !loading) { + showProgressView(false); + if (chatListView != null) { + chatListView.setEmptyView(null); + } + if (currentEncryptedChat == null) { + maxMessageId[0] = maxMessageId[1] = Integer.MAX_VALUE; + minMessageId[0] = minMessageId[1] = Integer.MIN_VALUE; + } else { + maxMessageId[0] = maxMessageId[1] = Integer.MIN_VALUE; + minMessageId[0] = minMessageId[1] = Integer.MAX_VALUE; + } + maxDate[0] = maxDate[1] = Integer.MIN_VALUE; + minDate[0] = minDate[1] = 0; + waitingForLoad.add(lastLoadIndex); + getMessagesController().loadMessages(dialog_id, mergeDialogId, false, 30, 0, 0, !cacheEndReached[0], minDate[0], classGuid, 0, 0, ChatObject.isChannel(currentChat), chatMode, threadMessageId, replyMaxReadId, lastLoadIndex++); + loading = true; + } else { + if (botButtons != null) { + botButtons = null; + if (chatActivityEnterView != null) { + chatActivityEnterView.setButtons(null, false); + } + } + if (currentEncryptedChat == null && currentUser != null && currentUser.bot && botUser == null) { + botUser = ""; + updateBottomOverlay(); + } + } + canShowPagedownButton = false; + updatePagedownButtonVisibility(true); + showMentionDownButton(false, true); + } + if (updated) { + if (chatMode == MODE_PINNED) { + if (avatarContainer != null) { + avatarContainer.setTitle(LocaleController.formatPluralString("PinnedMessagesCount", getPinnedMessagesCount())); + } + } + if (chatAdapter != null) { + int prevLoadingUpRow = chatAdapter.loadingUpRow; + int prevLoadingDownRow = chatAdapter.loadingDownRow; + for (int a = 0, N = removedIndexes.size(); a < N; a++) { + chatAdapter.notifyItemRemoved(removedIndexes.get(a)); + } + if (!isThreadChat() || messages.size() <= 3) { + removeUnreadPlane(false); + } + if (messages.isEmpty()) { + if (prevLoadingUpRow >= 0) { + chatAdapter.notifyItemRemoved(0); + } + if (prevLoadingDownRow >= 0) { + chatAdapter.notifyItemRemoved(0); + } + } else { + chatAdapter.notifyItemRangeChanged(chatAdapter.messagesStartRow, messages.size()); + } + } + updateVisibleRows(); + } else if (threadMessageId == 0) { + first_unread_id = 0; + last_message_id = 0; + createUnreadMessageAfterId = 0; + removeMessageObject(unreadMessageObject); + unreadMessageObject = null; + if (pagedownButtonCounter != null) { + pagedownButtonCounter.setVisibility(View.INVISIBLE); + } + } + if (updateScheduled) { + updateScheduledInterface(true); + } + } + private void replaceMessageObjects(ArrayList messageObjects, int loadIndex, boolean remove) { LongSparseArray newGroups = null; for (int a = 0; a < messageObjects.size(); a++) { MessageObject messageObject = messageObjects.get(a); + MessageObject pinnedOld = pinnedMessageObjects.get(messageObject.getId()); + if (pinnedOld != null) { + pinnedMessageObjects.put(messageObject.getId(), messageObject); + } MessageObject old = messagesDict[loadIndex].get(messageObject.getId()); - if (pinnedMessageObject != null && pinnedMessageObject.getId() == messageObject.getId()) { - pinnedMessageObject = messageObject; - updatePinnedMessageView(true); + if (pinnedMessageObjects.containsKey(messageObject.getId())) { + pinnedMessageObjects.put(messageObject.getId(), messageObject); + if (messageObject.getId() == currentPinnedMessageId) { + updatePinnedMessageView(true); + } } if (old == null || remove && old.messageOwner.date != messageObject.messageOwner.date) { continue; @@ -14135,7 +15060,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (old.getGroupId() != messageObject.getGroupId()) { groupedMessagesMap.put(messageObject.getGroupId(), groupedMessages); } - if (messageObject.photoThumbs == null || messageObject.photoThumbs.isEmpty()) { + if (!messageObject.isMusic() && !messageObject.isDocument() && (messageObject.photoThumbs == null || messageObject.photoThumbs.isEmpty())) { if (newGroups == null) { newGroups = new LongSparseArray<>(); } @@ -14185,7 +15110,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (dayArr.isEmpty()) { messagesByDays.remove(old.dateKey); messages.remove(index); + int prevLoadingUpRow = chatAdapter.loadingUpRow; + int prevLoadingDownRow = chatAdapter.loadingDownRow; chatAdapter.notifyItemRemoved(chatAdapter.messagesStartRow + index); + if (messages.isEmpty()) { + if (prevLoadingUpRow >= 0) { + chatAdapter.notifyItemRemoved(0); + } + if (prevLoadingDownRow >= 0) { + chatAdapter.notifyItemRemoved(0); + } + } } } } @@ -14351,19 +15286,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override protected void onBecomeFullyHidden() { - if (undoView != null) { - undoView.hide(true, 0); - } - if (topUndoView != null) { - topUndoView.hide(true, 0); - } + hideUndoViews(); } @Override public void onTransitionAnimationStart(boolean isOpen, boolean backward) { int[] alowedNotifications = null; if (isOpen) { - if (threadMessageId != 0) { + if (transitionAnimationIndex == 0) { alowedNotifications = new int[]{ NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.botKeyboardDidLoad, NotificationCenter.needDeleteDialog, @@ -14391,16 +15321,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } transitionAnimationIndex = getNotificationCenter().setAnimationInProgress(transitionAnimationIndex, alowedNotifications); + if (chatActivityEnterView != null && contentView != null && chatActivityEnterView.getAdjustPanLayoutHelper() != null && !chatActivityEnterView.getAdjustPanLayoutHelper().animationInProgress()) { + fixedKeyboardHeight = contentView.getKeyboardHeight(); + } + } + + @Override + protected void onTransitionAnimationProgress(boolean isOpen, float progress) { + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + if (isOpen) { + blurredView.setAlpha(1.0f - progress); + } else { + blurredView.setAlpha(progress); + } + } } @Override public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { if (isOpen) { - fragmentOpened = true; + if (!fragmentOpened) { + fragmentOpened = true; + updateMessagesVisiblePart(false); + } + if (backward) { + if (showPinBulletin && pinBulletin != null) { + pinBulletin.show(); + showPinBulletin = false; + } + } } - getNotificationCenter().onAnimationFinish(transitionAnimationIndex); + fixedKeyboardHeight = -1; if (isOpen) { + if (blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } openAnimationEnded = true; + getNotificationCenter().onAnimationFinish(transitionAnimationIndex); if (Build.VERSION.SDK_INT >= 21) { createChatAttachView(); } @@ -14426,7 +15384,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not BaseFragment fragment = parentLayout.fragmentsStack.get(a); if (fragment != this && fragment instanceof ChatActivity) { ChatActivity chatActivity = (ChatActivity) fragment; - if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.inScheduleMode == inScheduleMode && chatActivity.threadMessageId == threadMessageId) { + if (chatActivity.needRemovePreviousSameChatActivity && chatActivity.dialog_id == dialog_id && chatActivity.getChatMode() == getChatMode() && chatActivity.threadMessageId == threadMessageId) { fragment.removeSelfFromStack(); break; } @@ -14481,6 +15439,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } firstOpen = false; } + } else { + getNotificationCenter().onAnimationFinish(transitionAnimationIndex); } } @@ -14565,10 +15525,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateBottomOverlay() { - if (bottomOverlayChatText == null || inScheduleMode) { + if (bottomOverlayChatText == null || chatMode == MODE_SCHEDULED) { return; } - if (currentChat != null) { + if (chatMode == MODE_PINNED) { + boolean allowPin; + if (currentChat != null) { + allowPin = ChatObject.canPinMessages(currentChat); + } else { + if (userInfo != null) { + allowPin = userInfo.can_pin_message; + } else { + allowPin = false; + } + } + if (allowPin) { + bottomOverlayChatText.setTag(1); + bottomOverlayChatText.setText(LocaleController.getString("UnpinAllMessages", R.string.UnpinAllMessages)); + } else { + bottomOverlayChatText.setTag(null); + bottomOverlayChatText.setText(LocaleController.getString("HidePinnedMessages", R.string.HidePinnedMessages)); + } + showBottomOverlayProgress(false, false); + } else if (currentChat != null) { if (!isThreadChat()) { if (ChatObject.isChannel(currentChat) && !(currentChat instanceof TLRPC.TL_channelForbidden)) { if (ChatObject.isNotInChat(currentChat)) { @@ -14651,7 +15630,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not muteItem.setVisibility(View.VISIBLE); } } - if (currentChat != null && !isThreadChat() && (ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) || + if (chatMode == MODE_PINNED || + currentChat != null && !isThreadChat() && (ChatObject.isNotInChat(currentChat) || !ChatObject.canWriteToChat(currentChat)) || currentUser != null && (UserObject.isDeleted(currentUser) || userBlocked || UserObject.isReplyUser(currentUser))) { if (chatActivityEnterView.isEditingMessage()) { chatActivityEnterView.setVisibility(View.VISIBLE); @@ -14801,6 +15781,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean hidePinnedMessageView(boolean animated) { if (pinnedMessageView.getTag() == null) { + for (int a = 0; a < pinnedNextAnimation.length; a++) { + if (pinnedNextAnimation[a] != null) { + pinnedNextAnimation[a].cancel(); + pinnedNextAnimation[a] = null; + } + } + setPinnedTextTranslationX = false; pinnedMessageView.setTag(1); if (pinnedMessageViewAnimator != null) { pinnedMessageViewAnimator.cancel(); @@ -14844,36 +15831,92 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updatePinnedMessageView(boolean animated) { - if (pinnedMessageView == null || inScheduleMode) { + updatePinnedMessageView(animated, 0); + } + + private void updatePinnedListButton(boolean animated) { + if (isThreadChat() || pinnedListButton == null) { + return; + } + boolean show = pinnedMessageIds.size() > 1; + boolean visible = pinnedListButton.getTag() != null; + if (show != visible) { + if (pinnedListAnimator != null) { + pinnedListAnimator.cancel(); + pinnedListAnimator = null; + } + if (animated) { + if (show) { + pinnedListButton.setVisibility(View.VISIBLE); + } else { + closePinned.setVisibility(View.VISIBLE); + } + pinnedListAnimator = new AnimatorSet(); + pinnedListAnimator.playTogether( + ObjectAnimator.ofFloat(pinnedListButton, View.ALPHA, show ? 1.0f : 0.0f), + ObjectAnimator.ofFloat(pinnedListButton, View.SCALE_X, show ? 1.0f : 0.4f), + ObjectAnimator.ofFloat(pinnedListButton, View.SCALE_Y, show ? 1.0f : 0.4f), + ObjectAnimator.ofFloat(closePinned, View.ALPHA, show ? 0.0f : 1.0f), + ObjectAnimator.ofFloat(closePinned, View.SCALE_X, show ? 0.4f : 1.0f), + ObjectAnimator.ofFloat(closePinned, View.SCALE_Y, show ? 0.4f : 1.0f)); + pinnedListAnimator.setDuration(180); + pinnedListAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + pinnedListAnimator = null; + if (show) { + closePinned.setVisibility(View.INVISIBLE); + } else { + pinnedListButton.setVisibility(View.INVISIBLE); + } + } + }); + pinnedListAnimator.start(); + } else { + closePinned.setAlpha(show ? 0.0f : 1.0f); + closePinned.setScaleX(show ? 0.4f : 1.0f); + closePinned.setScaleY(show ? 0.4f : 1.0f); + closePinned.setVisibility(show ? View.INVISIBLE : View.VISIBLE); + pinnedListButton.setAlpha(show ? 1.0f : 0.0f); + pinnedListButton.setScaleX(show ? 1.0f : 0.4f); + pinnedListButton.setScaleY(show ? 1.0f : 0.4f); + pinnedListButton.setVisibility(show ? View.VISIBLE : View.INVISIBLE); + } + pinnedListButton.setTag(show ? 1 : null); + } + if (pinnedLineView != null) { + if (isThreadChat()) { + pinnedLineView.set(0, 1, false); + } else { + int position = Collections.binarySearch(pinnedMessageIds, currentPinnedMessageId, Comparator.reverseOrder()); + pinnedLineView.set(pinnedMessageIds.size() - 1 - position, pinnedMessageIds.size(), animated); + } + } + } + + private void updatePinnedMessageView(boolean animated, int animateToNext) { + if (pinnedMessageView == null || chatMode != 0) { return; } int pinned_msg_id; boolean changed = false; + MessageObject pinnedMessageObject; if (isThreadChat()) { - if (!replyMessageVisible) { + if (!threadMessageVisible) { pinnedMessageObject = threadMessageObject; pinned_msg_id = threadMessageId; } else { pinnedMessageObject = null; pinned_msg_id = 0; } - } else if (chatInfo != null) { - if (pinnedMessageObject != null && chatInfo.pinned_msg_id != pinnedMessageObject.getId()) { - pinnedMessageObject = null; + } else if (currentPinnedMessageId != 0 && !pinnedMessageIds.isEmpty()) { + pinnedMessageObject = pinnedMessageObjects.get(currentPinnedMessageId); + if (pinnedMessageObject == null) { + pinnedMessageObject = messagesDict[0].get(currentPinnedMessageId); } - if (chatInfo.pinned_msg_id != 0 && pinnedMessageObject == null) { - pinnedMessageObject = messagesDict[0].get(chatInfo.pinned_msg_id); - } - pinned_msg_id = chatInfo.pinned_msg_id; - } else if (userInfo != null) { - if (pinnedMessageObject != null && userInfo.pinned_msg_id != pinnedMessageObject.getId()) { - pinnedMessageObject = null; - } - if (userInfo.pinned_msg_id != 0 && pinnedMessageObject == null) { - pinnedMessageObject = messagesDict[0].get(userInfo.pinned_msg_id); - } - pinned_msg_id = userInfo.pinned_msg_id; + pinned_msg_id = currentPinnedMessageId; } else { + pinnedMessageObject = null; pinned_msg_id = 0; } SharedPreferences preferences = MessagesController.getNotificationsSettings(currentAccount); @@ -14884,6 +15927,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not changed = hidePinnedMessageView(animated); if (headerItem != null) headerItem.showSubItem(show_pinned); } else { + updatePinnedListButton(animated); if (headerItem != null) headerItem.hideSubItem(show_pinned); if (pinnedMessageObject != null) { if (pinnedMessageView.getTag() != null) { @@ -14900,21 +15944,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onAnimationUpdate(ValueAnimator animation) { - float translationY = (float) animation.getAnimatedValue(); - if (!isThreadChat() && !wasManualScroll && unreadMessageObject != null && chatListView != null) { - int msgIndex = position - chatAdapter.messagesStartRow; - if (msgIndex < 0 || msgIndex >= messages.size() || messages.get(msgIndex) != unreadMessageObject) { - position = chatAdapter.messagesStartRow + messages.indexOf(unreadMessageObject); - } - if (position >= 0) { - View v = chatLayoutManager.findViewByPosition(position); - float top = pinnedMessageView.getBottom() + translationY - chatListView.getTop(); - if (v != null && top > v.getTop() + AndroidUtilities.dp(9)) { - chatListView.scrollBy(0, (int) (v.getTop() + AndroidUtilities.dp(9) - top)); - } - } - } - pinnedMessageEnterOffset = translationY; + pinnedMessageEnterOffset = (float) animation.getAnimatedValue(); invalidateChatListViewTopPadding(); chatListView.invalidate(); } @@ -14942,15 +15972,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { pinnedMessageEnterOffset = 0; invalidateChatListViewTopPadding(); - chatListView.invalidate(); - if (firstLoading) { - updateChatListViewTopPadding(); - } pinnedMessageView.setVisibility(View.VISIBLE); } } - FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) pinnedMessageNameTextView.getLayoutParams(); - FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pinnedMessageTextView.getLayoutParams(); + for (int a = 0; a < pinnedNextAnimation.length; a++) { + if (pinnedNextAnimation[a] != null) { + pinnedNextAnimation[a].cancel(); + pinnedNextAnimation[a] = null; + } + } + setPinnedTextTranslationX = false; + SimpleTextView nameTextView = pinnedNameTextView[animateToNext != 0 && loadedPinnedMessagesCount == 2 ? 1 : 0]; + SimpleTextView messageTextView = pinnedMessageTextView[animateToNext != 0 ? 1 : 0]; + FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) pinnedNameTextView[0].getLayoutParams(); + FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pinnedNameTextView[1].getLayoutParams(); + FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) pinnedCounterTextView.getLayoutParams(); + FrameLayout.LayoutParams layoutParams4 = (FrameLayout.LayoutParams) pinnedMessageTextView[0].getLayoutParams(); + FrameLayout.LayoutParams layoutParams5 = (FrameLayout.LayoutParams) pinnedMessageTextView[1].getLayoutParams(); int cacheType = 1; int size = 0; @@ -14973,29 +16011,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (photoSize == thumbPhotoSize) { thumbPhotoSize = null; } - if (photoSize == null || photoSize instanceof TLRPC.TL_photoSizeEmpty || photoSize.location instanceof TLRPC.TL_fileLocationUnavailable || pinnedMessageObject.isAnyKindOfSticker()) { - pinnedMessageImageView.setImageBitmap(null); + boolean noImage; + int prevMargin = layoutParams1.leftMargin; + if (noImage = (photoSize == null || photoSize instanceof TLRPC.TL_photoSizeEmpty || photoSize.location instanceof TLRPC.TL_fileLocationUnavailable || pinnedMessageObject.isAnyKindOfSticker() || pinnedMessageObject.isSecretMedia())) { pinnedImageLocation = null; pinnedImageLocationObject = null; - pinnedMessageImageView.setVisibility(View.INVISIBLE); - layoutParams1.leftMargin = layoutParams2.leftMargin = AndroidUtilities.dp(18); + if (animateToNext == 0) { + pinnedMessageImageView[0].setImageBitmap(null); + pinnedMessageImageView[0].setVisibility(View.INVISIBLE); + } + layoutParams1.leftMargin = layoutParams2.leftMargin = layoutParams3.leftMargin = layoutParams4.leftMargin = layoutParams5.leftMargin = AndroidUtilities.dp(18); } else { if (pinnedMessageObject.isRoundVideo()) { - pinnedMessageImageView.setRoundRadius(AndroidUtilities.dp(16)); + pinnedMessageImageView[1].setRoundRadius(AndroidUtilities.dp(16)); } else { - pinnedMessageImageView.setRoundRadius(0); + pinnedMessageImageView[1].setRoundRadius(AndroidUtilities.dp(2)); } pinnedImageSize = size; pinnedImageCacheType = cacheType; pinnedImageLocation = photoSize; pinnedImageThumbLocation = thumbPhotoSize; pinnedImageLocationObject = photoSizeObject; - pinnedMessageImageView.setImage(ImageLocation.getForObject(pinnedImageLocation, photoSizeObject), "50_50", ImageLocation.getForObject(thumbPhotoSize, photoSizeObject), "50_50_b", null, size, cacheType, pinnedMessageObject); - pinnedMessageImageView.setVisibility(View.VISIBLE); - layoutParams1.leftMargin = layoutParams2.leftMargin = AndroidUtilities.dp(55); + pinnedMessageImageView[1].setImage(ImageLocation.getForObject(pinnedImageLocation, photoSizeObject), "50_50", ImageLocation.getForObject(thumbPhotoSize, photoSizeObject), "50_50_b", null, size, cacheType, pinnedMessageObject); + pinnedMessageImageView[1].setVisibility(View.VISIBLE); + if (animateToNext != 0) { + pinnedMessageImageView[1].setAlpha(0.0f); + } + layoutParams1.leftMargin = layoutParams2.leftMargin = layoutParams3.leftMargin = layoutParams4.leftMargin = layoutParams5.leftMargin = AndroidUtilities.dp(55); } - pinnedMessageNameTextView.setLayoutParams(layoutParams1); - pinnedMessageTextView.setLayoutParams(layoutParams2); + pinnedNameTextView[0].setLayoutParams(layoutParams1); + pinnedNameTextView[1].setLayoutParams(layoutParams2); + pinnedCounterTextView.setLayoutParams(layoutParams3); + pinnedMessageTextView[0].setLayoutParams(layoutParams4); + pinnedMessageTextView[1].setLayoutParams(layoutParams5); if (threadMessageId != 0) { MessagesController messagesController = MessagesController.getInstance(currentAccount); @@ -15036,17 +16084,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chat = messagesController.getChat(threadMessageObject.messageOwner.peer_id.channel_id); } if (user != null) { - pinnedMessageNameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); + nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); } else if (chat != null) { - pinnedMessageNameTextView.setText(chat.title); + nameTextView.setText(chat.title); } - } else if (pinnedMessageObject.type == MessageObject.TYPE_POLL) { - pinnedMessageNameTextView.setText(LocaleController.getString("PinnedPoll", R.string.PinnedPoll)); } else { - pinnedMessageNameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + if (currentPinnedMessageIndex[0] == 0 || loadedPinnedMessagesCount != 2) { + nameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + } else { + nameTextView.setText(LocaleController.getString("PreviousPinnedMessage", R.string.PreviousPinnedMessage)); + } + if (currentPinnedMessageIndex[0] != 0) { + int total = getPinnedMessagesCount(); + pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), animated && pinnedCounterTextView.getTag() == null); + } } if (pinnedMessageObject.type == 14) { - pinnedMessageTextView.setText(String.format("%s - %s", pinnedMessageObject.getMusicAuthor(), pinnedMessageObject.getMusicTitle())); + messageTextView.setText(String.format("%s - %s", pinnedMessageObject.getMusicAuthor(), pinnedMessageObject.getMusicTitle())); } else if (pinnedMessageObject.type == MessageObject.TYPE_POLL) { TLRPC.TL_messageMediaPoll poll = (TLRPC.TL_messageMediaPoll) pinnedMessageObject.messageOwner.media; String mess = poll.poll.question; @@ -15054,31 +16108,300 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - pinnedMessageTextView.setText(mess); + messageTextView.setText(mess); } else if (pinnedMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGame) { - pinnedMessageTextView.setText(Emoji.replaceEmoji(pinnedMessageObject.messageOwner.media.game.title, pinnedMessageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + messageTextView.setText(Emoji.replaceEmoji(pinnedMessageObject.messageOwner.media.game.title, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); } else if (!TextUtils.isEmpty(pinnedMessageObject.caption)) { String mess = pinnedMessageObject.caption.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - pinnedMessageTextView.setText(Emoji.replaceEmoji(mess, pinnedMessageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + messageTextView.setText(Emoji.replaceEmoji(mess, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); } else if (pinnedMessageObject.messageText != null) { String mess = pinnedMessageObject.messageText.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } mess = mess.replace('\n', ' '); - pinnedMessageTextView.setText(Emoji.replaceEmoji(mess, pinnedMessageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + messageTextView.setText(Emoji.replaceEmoji(mess, messageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + } + if (animateToNext != 0) { + pinnedNextAnimation[0] = new AnimatorSet(); + pinnedNextAnimation[1] = new AnimatorSet(); + ArrayList animators = new ArrayList<>(); + ArrayList animators2 = new ArrayList<>(); + messageTextView.setVisibility(View.VISIBLE); + nameTextView.setVisibility(View.VISIBLE); + + if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (pinnedCounterTextView.getTag() == null) { + animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.ALPHA, 1.0f, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_Y, 0.0f, -AndroidUtilities.dp(4))); + pinnedCounterTextView.setTag(1); + } + } else { + if (pinnedCounterTextView.getTag() != null) { + pinnedCounterTextView.setVisibility(View.VISIBLE); + pinnedCounterTextView.setAlpha(0.0f); + animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_Y, -AndroidUtilities.dp(4), 0)); + pinnedCounterTextView.setTag(null); + } + } + + if (loadedPinnedMessagesCount == 2 && !TextUtils.equals(nameTextView.getText(), pinnedNameTextView[0].getText())) { + nameTextView.setAlpha(0); + animators.add(ObjectAnimator.ofFloat(nameTextView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.ALPHA, 1.0f, 0.0f)); + animators.add(ObjectAnimator.ofFloat(nameTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); + } else { + if (nameTextView != pinnedNameTextView[0]) { + nameTextView.setAlpha(1.0f); + pinnedNameTextView[0].setAlpha(0.0f); + nameTextView.setTranslationY(0.0f); + pinnedNameTextView[0].setTranslationY(0.0f); + } else { + nameTextView.setAlpha(1.0f); + nameTextView.setTranslationY(0.0f); + pinnedNameTextView[1].setTranslationY(0.0f); + pinnedNameTextView[1].setAlpha(0.0f); + } + } + + boolean animateText; + if (!TextUtils.equals(messageTextView.getText(), pinnedMessageTextView[0].getText())) { + messageTextView.setAlpha(0); + animators.add(ObjectAnimator.ofFloat(messageTextView, View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[0], View.ALPHA, 1.0f, 0.0f)); + if (animateText = forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animators2.add(ObjectAnimator.ofFloat(messageTextView, View.TRANSLATION_Y, AndroidUtilities.dp(4), AndroidUtilities.dp(-2))); + } else { + animators.add(ObjectAnimator.ofFloat(messageTextView, View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 4 : -4), 0.0f)); + } + animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -4 : 4))); + } else { + animateText = false; + messageTextView.setAlpha(1.0f); + pinnedMessageTextView[0].setAlpha(0.0f); + messageTextView.setTranslationY(0.0f); + pinnedMessageTextView[0].setTranslationY(0.0f); + } + + BackupImageView animateImage; + if (layoutParams1.leftMargin != prevMargin) { + animateImage = null; + setPinnedTextTranslationX = true; + int diff = prevMargin - layoutParams1.leftMargin; + animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[0], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageTextView[1], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[0], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedNameTextView[1], View.TRANSLATION_X, diff, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedCounterTextView, View.TRANSLATION_X, pinnedCounterTextViewX + diff, pinnedCounterTextViewX)); + if (diff > 0) { + pinnedMessageImageView[0].setAlpha(1f); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[0], View.ALPHA, 1.0f, 0.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[0], View.SCALE_X, 1.0f, 0.7f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[0], View.SCALE_Y, 1.0f, 0.7f)); + } else { + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.SCALE_X, 0.7f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.SCALE_Y, 0.7f, 1.0f)); + } + } else { + setPinnedTextTranslationX = false; + messageTextView.setTranslationX(0); + pinnedMessageTextView[0].setTranslationX(0); + nameTextView.setTranslationX(0); + pinnedNameTextView[0].setTranslationX(0); + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + pinnedMessageImageView[1].setAlpha(1.0f); + if (!noImage) { + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.ALPHA, 0.0f, 1.0f)); + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[0], View.ALPHA, 1.0f, 0.0f)); + if (forceScrollToFirst && loadedPinnedMessagesCount > 5) { + animateImage = pinnedMessageImageView[1]; + animators2.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.TRANSLATION_Y, AndroidUtilities.dp(3), AndroidUtilities.dp(-2))); + } else { + animateImage = null; + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[1], View.TRANSLATION_Y, AndroidUtilities.dp(animateToNext == 2 ? 3 : -3), 0.0f)); + } + animators.add(ObjectAnimator.ofFloat(pinnedMessageImageView[0], View.TRANSLATION_Y, 0.0f, AndroidUtilities.dp(animateToNext == 2 ? -3 : 3))); + } else { + animateImage = null; + } + } + + pinnedNextAnimation[1].addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationCancel(Animator animation) { + pinnedNextAnimation[1] = null; + pinnedMessageImageView[1].setTranslationY(0); + } + + @Override + public void onAnimationEnd(Animator animation) { + if (animation.equals(pinnedNextAnimation[1])) { + if (animateText || animateImage != null) { + pinnedNextAnimation[1] = new AnimatorSet(); + pinnedNextAnimation[1].setInterpolator(CubicBezierInterpolator.EASE_OUT); + pinnedNextAnimation[1].setDuration(180); + ArrayList animators1 = new ArrayList<>(); + if (animateText) { + animators1.add(ObjectAnimator.ofFloat(messageTextView, View.TRANSLATION_Y, 0.0f)); + } + if (animateImage != null) { + animators1.add(ObjectAnimator.ofFloat(animateImage, View.TRANSLATION_Y, 0.0f)); + } + pinnedNextAnimation[1].addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animateText) { + messageTextView.setTranslationY(0.0f); + } + if (animateImage != null) { + animateImage.setTranslationY(0.0f); + } + pinnedNextAnimation[1] = null; + } + }); + pinnedNextAnimation[1].playTogether(animators1); + pinnedNextAnimation[1].start(); + } else { + pinnedNextAnimation[1] = null; + } + } + } + }); + + pinnedNextAnimation[1].setDuration(180); + if (forceScrollToFirst && loadedPinnedMessagesCount > 5) { + pinnedNextAnimation[1].setInterpolator(CubicBezierInterpolator.EASE_OUT); + } + pinnedNextAnimation[1].playTogether(animators2); + + pinnedNextAnimation[0].playTogether(animators); + pinnedNextAnimation[0].addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (pinnedCounterTextView.getTag() != null) { + pinnedCounterTextView.setVisibility(View.INVISIBLE); + int total = getPinnedMessagesCount(); + pinnedCounterTextView.setNumber(Math.min(total - 1, Math.max(1, total - currentPinnedMessageIndex[0])), false); + } else { + pinnedCounterTextView.setAlpha(1.0f); + } + pinnedCounterTextView.setTranslationY(0.0f); + pinnedMessageTextView[0].setTranslationX(0); + pinnedMessageTextView[1].setTranslationX(0); + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + if (!animateText) { + messageTextView.setTranslationY(0.0f); + } + nameTextView.setTranslationY(0.0f); + pinnedNameTextView[0].setTranslationX(0); + pinnedNameTextView[1].setTranslationX(0); + pinnedMessageImageView[1].setAlpha(1.0f); + pinnedMessageImageView[1].setScaleX(1f); + pinnedMessageImageView[1].setScaleY(1f); + pinnedMessageImageView[0].setAlpha(1.0f); + pinnedMessageImageView[0].setScaleX(1f); + pinnedMessageImageView[0].setScaleY(1f); + pinnedMessageTextView[1] = pinnedMessageTextView[0]; + pinnedMessageTextView[0] = messageTextView; + pinnedMessageTextView[1].setVisibility(View.INVISIBLE); + if (nameTextView != pinnedNameTextView[0]) { + pinnedNameTextView[1] = pinnedNameTextView[0]; + pinnedNameTextView[0] = nameTextView; + pinnedNameTextView[1].setVisibility(View.INVISIBLE); + } + if (noImage) { + pinnedMessageImageView[1].setImageBitmap(null); + pinnedMessageImageView[1].setVisibility(View.INVISIBLE); + } + BackupImageView backupImageView = pinnedMessageImageView[1]; + pinnedMessageImageView[1] = pinnedMessageImageView[0]; + pinnedMessageImageView[0] = backupImageView; + pinnedMessageImageView[1].setAlpha(1.0f); + pinnedMessageImageView[1].setScaleX(1f); + pinnedMessageImageView[1].setScaleY(1f); + pinnedMessageImageView[1].setVisibility(View.INVISIBLE); + + pinnedNextAnimation[0] = null; + setPinnedTextTranslationX = false; + } + }); + pinnedNextAnimation[0].setDuration(180); + if (!setPinnedTextTranslationX) { + pinnedNextAnimation[0].start(); + pinnedNextAnimation[1].start(); + } + } else { + if (loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0) { + if (pinnedCounterTextView.getTag() == null) { + pinnedCounterTextView.setAlpha(0.0f); + pinnedCounterTextView.setVisibility(View.INVISIBLE); + pinnedCounterTextView.setTag(1); + + } + } else { + if (pinnedCounterTextView.getTag() != null) { + pinnedCounterTextView.setVisibility(View.VISIBLE); + pinnedCounterTextView.setAlpha(1.0f); + pinnedCounterTextView.setTag(null); + } + } + pinnedCounterTextView.setTranslationY(0.0f); + pinnedCounterTextView.setTranslationX(pinnedCounterTextViewX); + + pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); + + messageTextView.setVisibility(View.VISIBLE); + messageTextView.setAlpha(1.0f); + messageTextView.setTranslationX(0); + messageTextView.setTranslationY(0); + nameTextView.setVisibility(View.VISIBLE); + nameTextView.setAlpha(1.0f); + nameTextView.setTranslationX(0); + nameTextView.setTranslationY(0); + pinnedMessageTextView[1].setVisibility(View.INVISIBLE); + pinnedMessageTextView[1].setTranslationX(0); + pinnedMessageTextView[1].setTranslationY(0); + pinnedNameTextView[1].setVisibility(View.INVISIBLE); + pinnedNameTextView[1].setTranslationX(0); + pinnedNameTextView[1].setTranslationY(0); + pinnedMessageImageView[0].setVisibility(View.INVISIBLE); + BackupImageView backupImageView = pinnedMessageImageView[1]; + pinnedMessageImageView[1] = pinnedMessageImageView[0]; + pinnedMessageImageView[0] = backupImageView; + pinnedMessageImageView[0].setAlpha(1.0f); + pinnedMessageImageView[0].setScaleX(1f); + pinnedMessageImageView[0].setScaleY(1f); + pinnedMessageImageView[0].setTranslationY(0); + pinnedMessageImageView[1].setAlpha(1.0f); + pinnedMessageImageView[1].setScaleX(1f); + pinnedMessageImageView[1].setScaleY(1f); + pinnedMessageImageView[1].setTranslationY(0); + } + if (isThreadChat()) { + pinnedLineView.set(0, 1, false); + } else { + int position = Collections.binarySearch(pinnedMessageIds, currentPinnedMessageId, Comparator.reverseOrder()); + pinnedLineView.set(pinnedMessageIds.size() - 1 - position, pinnedMessageIds.size(), animateToNext != 0); } } else { + pinnedCounterTextView.setVisibility(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? View.INVISIBLE : View.VISIBLE); + pinnedCounterTextView.setAlpha(loadedPinnedMessagesCount == 2 || currentPinnedMessageIndex[0] == 0 ? 0.0f : 1.0f); pinnedImageLocation = null; pinnedImageLocationObject = null; changed = hidePinnedMessageView(animated); - if (loadingPinnedMessage != pinned_msg_id) { - loadingPinnedMessage = pinned_msg_id; - getMediaDataController().loadPinnedMessage(dialog_id, ChatObject.isChannel(currentChat) ? currentChat.id : 0, pinned_msg_id, true); + if (loadingPinnedMessages.indexOfKey(pinned_msg_id) < 0) { + loadingPinnedMessages.put(pinned_msg_id, true); + ArrayList ids = new ArrayList<>(); + ids.add(pinned_msg_id); + getMediaDataController().loadPinnedMessages(dialog_id, ChatObject.isChannel(currentChat) ? currentChat.id : 0, ids, true); } } } @@ -15088,7 +16411,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateTopPanel(boolean animated) { - if (topChatPanelView == null || inScheduleMode) { + if (topChatPanelView == null || chatMode != 0) { return; } @@ -15290,23 +16613,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checkListViewPaddings(); } - private void checkListViewPaddingsInternal() { - if (chatLayoutManager == null) { - return; - } - try { - if (chatListViewPaddingTop != AndroidUtilities.dp(48) && (!isThreadChat() && pinnedMessageView != null && pinnedMessageView.getTag() == null || topChatPanelView != null && topChatPanelView.getTag() == null)) { - chatListViewPaddingTop = AndroidUtilities.dp(48); - invalidateChatListViewTopPadding(); - } else if (chatListViewPaddingTop != 0 && (isThreadChat() || pinnedMessageView == null || pinnedMessageView.getTag() != null) && (topChatPanelView == null || topChatPanelView.getTag() != null)) { - chatListViewPaddingTop = 0; - invalidateChatListViewTopPadding(); - } - } catch (Exception e) { - FileLog.e(e); - } - } - private void checkListViewPaddings() { if (!wasManualScroll && unreadMessageObject != null) { int pos = messages.indexOf(unreadMessageObject); @@ -15322,7 +16628,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } AndroidUtilities.runOnUIThread(checkPaddingsRunnable = () -> { checkPaddingsRunnable = null; - checkListViewPaddingsInternal(); + invalidateChatListViewTopPadding(); }); } } @@ -15355,7 +16661,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not super.setInPreviewMode(value); if (avatarContainer != null) { avatarContainer.setOccupyStatusBar(!value); - avatarContainer.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !value ? 56 : 0, 0, 40, 0)); + avatarContainer.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !value ? 56 : (chatMode == MODE_PINNED ? 10 : 0), 0, 40, 0)); } if (chatActivityEnterView != null) { chatActivityEnterView.setVisibility(!value ? View.VISIBLE : View.INVISIBLE); @@ -15408,6 +16714,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onResume() { super.onResume(); + if (parentLayout != null && !parentLayout.isInPreviewMode() && blurredView != null && blurredView.getVisibility() == View.VISIBLE) { + blurredView.setVisibility(View.GONE); + blurredView.setBackground(null); + } activityResumeTime = System.currentTimeMillis(); AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); @@ -15442,13 +16752,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyImageView.setImage(ImageLocation.getForObject(replyImageLocation, replyImageLocationObject), "50_50", ImageLocation.getForObject(replyImageThumbLocation, replyImageLocationObject), "50_50_b", null, replyImageSize, replyImageCacheType, replyingMessageObject); } if (pinnedImageLocation != null && pinnedMessageImageView != null) { - pinnedMessageImageView.setImage(ImageLocation.getForObject(pinnedImageLocation, pinnedImageLocationObject), "50_50", ImageLocation.getForObject(pinnedImageThumbLocation, pinnedImageLocationObject), "50_50_b", null, pinnedImageSize, pinnedImageCacheType, pinnedMessageObject); + MessageObject pinnedMessageObject = pinnedMessageObjects.get(currentPinnedMessageId); + pinnedMessageImageView[0].setImage(ImageLocation.getForObject(pinnedImageLocation, pinnedImageLocationObject), "50_50", ImageLocation.getForObject(pinnedImageThumbLocation, pinnedImageLocationObject), "50_50_b", null, pinnedImageSize, pinnedImageCacheType, pinnedMessageObject); } - if (!inScheduleMode) { + if (chatMode == 0) { getNotificationsController().setOpenedDialogId(dialog_id); } - getMessagesController().setLastVisibleDialogId(dialog_id, inScheduleMode, true); + getMessagesController().setLastVisibleDialogId(dialog_id, chatMode == MODE_SCHEDULED, true); if (scrollToTopOnResume) { if (scrollToTopUnReadOnResume && scrollToMessage != null) { if (chatListView != null) { @@ -15534,11 +16845,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MediaController.getInstance().stopRaiseToEarSensors(this, true); paused = true; wasPaused = true; - if (!inScheduleMode) { + if (chatMode == 0) { getNotificationsController().setOpenedDialogId(0); } Bulletin.removeDelegate(this); - getMessagesController().setLastVisibleDialogId(dialog_id, inScheduleMode, false); + getMessagesController().setLastVisibleDialogId(dialog_id, chatMode == MODE_SCHEDULED, false); CharSequence draftMessage = null; MessageObject replyMessage = null; boolean searchWebpage = true; @@ -15561,7 +16872,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (contentView != null) { contentView.onPause(); } - if (!inScheduleMode) { + if (chatMode == 0) { CharSequence[] message = new CharSequence[]{draftMessage}; ArrayList entities = getMediaDataController().getEntities(message, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 101); getMediaDataController().saveDraft(dialog_id, threadMessageId, message[0], entities, replyMessage != null ? replyMessage.messageOwner : null, !searchWebpage); @@ -15638,13 +16949,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatLeaveTime = System.currentTimeMillis(); updateInformationForScreenshotDetector(); } - - if (undoView != null) { - undoView.hide(true, 0); - } - if (topUndoView != null) { - topUndoView.hide(true, 0); - } + hideUndoViews(); } if (chatListItemAniamtor != null) { @@ -15659,7 +16964,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void applyDraftMaybe(boolean canClear) { - if (chatActivityEnterView == null || inScheduleMode) { + if (chatActivityEnterView == null || chatMode != 0) { return; } TLRPC.DraftMessage draftMessage = getMediaDataController().getDraft(dialog_id, threadMessageId); @@ -15800,7 +17105,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (AndroidUtilities.isSmallTablet() && ApplicationLoader.applicationContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { actionBar.setBackButtonDrawable(new BackDrawable(false)); if (fragmentContextView != null && fragmentContextView.getParent() == null) { - ((ViewGroup) fragmentView).addView(fragmentContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + ((ViewGroup) fragmentView).addView(fragmentContextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); } } else { actionBar.setBackButtonDrawable(new BackDrawable(parentLayout == null || parentLayout.fragmentsStack.isEmpty() || parentLayout.fragmentsStack.get(0) == ChatActivity.this || parentLayout.fragmentsStack.size() == 1)); @@ -15947,7 +17252,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (finalSelectedObject == null && (selectedMessagesIds[0].size() + selectedMessagesIds[1].size()) == 0) { return; } - AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, inScheduleMode, loadParticipant, () -> { + AlertsCreator.createDeleteMessagesAlert(this, currentUser, currentChat, currentEncryptedChat, chatInfo, mergeDialogId, finalSelectedObject, selectedMessagesIds, finalSelectedGroup, chatMode == MODE_SCHEDULED, loadParticipant, () -> { hideActionMode(); updatePinnedMessageView(true); }); @@ -15963,6 +17268,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cantDeleteMessagesCount = 0; canEditMessagesCount = 0; cantForwardMessagesCount = 0; + canSaveMusicCount = 0; + canSaveDocumentsCount = 0; + cantSaveMessagesCount = 0; if (chatActivityEnterView != null) { EditTextCaption editTextCaption = chatActivityEnterView.getEditField(); if (chatActivityEnterView.getVisibility() == View.VISIBLE) { @@ -15978,6 +17286,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (textSelectionHint != null) { textSelectionHint.hide(); } + if (chatActivityEnterView != null) { + chatActivityEnterView.preventInput = false; + } textSelectionHintWasShowed = false; } @@ -16023,7 +17334,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (single) { if (message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { if (message.getReplyMsgId() != 0) { - scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, 0, true); + scrollToMessageId(message.getReplyMsgId(), message.messageOwner.id, true, 0, false); } else { Toast.makeText(getParentActivity(), LocaleController.getString("MessageNotFound", R.string.MessageNotFound), Toast.LENGTH_SHORT).show(); } @@ -16056,12 +17367,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean allowChatActions = true; boolean allowPin; - if (inScheduleMode || isThreadChat()) { + if (chatMode == MODE_SCHEDULED || isThreadChat()) { allowPin = false; } else if (currentChat != null) { allowPin = message.getDialogId() != mergeDialogId && ChatObject.canPinMessages(currentChat); } else if (currentEncryptedChat == null) { - if (userInfo != null) { + if (UserObject.isDeleted(currentUser)) { + allowPin = false; + } else if (userInfo != null) { allowPin = userInfo.can_pin_message; } else { allowPin = false; @@ -16070,7 +17383,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not allowPin = false; } allowPin = allowPin && message.getId() > 0 && (message.messageOwner.action == null || message.messageOwner.action instanceof TLRPC.TL_messageActionEmpty); - boolean allowUnpin = message.getDialogId() != mergeDialogId && allowPin && (chatInfo != null && chatInfo.pinned_msg_id == message.getId() || userInfo != null && userInfo.pinned_msg_id == message.getId()); + boolean allowUnpin = message.getDialogId() != mergeDialogId && allowPin && (pinnedMessageObjects.containsKey(message.getId()) || groupedMessages != null && !groupedMessages.messages.isEmpty() && pinnedMessageObjects.containsKey(groupedMessages.messages.get(0).getId())); boolean allowEdit = message.canEditMessage(currentChat) && !chatActivityEnterView.hasAudioToSend() && message.getDialogId() != mergeDialogId; if (allowEdit && groupedMessages != null) { int captionsCount = 0; @@ -16085,7 +17398,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } allowEdit = captionsCount < 2; } - if (inScheduleMode || threadMessageObjects != null && threadMessageObjects.contains(message) || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || + if (chatMode == MODE_SCHEDULED || threadMessageObjects != null && threadMessageObjects.contains(message) || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || type == 1 && message.getDialogId() == mergeDialogId || message.messageOwner.action instanceof TLRPC.TL_messageActionSecureValuesSent || currentEncryptedChat == null && message.getId() < 0 || @@ -16129,12 +17442,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(8); icons.add(R.drawable.baseline_reply_24); } - if (currentChat.has_link && !isThreadChat() && !inScheduleMode && currentChat.has_link && currentChat.megagroup && message.canViewThread()) { - if (message.hasReplies()) { - items.add(LocaleController.formatPluralString("ViewReplies", message.getRepliesCount())); - } else { - items.add(LocaleController.getString("ViewThread", R.string.ViewThread)); - } + if (!isThreadChat() && chatMode != MODE_SCHEDULED && message.hasReplies() && currentChat.megagroup && message.canViewThread()) { + items.add(LocaleController.formatPluralString("ViewReplies", message.getRepliesCount())); options.add(27); icons.add(R.drawable.msg_viewreplies); } @@ -16164,7 +17473,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.baseline_reply_24); } } - if (message.canDeleteMessage(inScheduleMode, currentChat) && (threadMessageObjects == null || !threadMessageObjects.contains(message))) { + if (message.canDeleteMessage(chatMode == MODE_SCHEDULED, currentChat) && (threadMessageObjects == null || !threadMessageObjects.contains(message))) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); icons.add(R.drawable.baseline_delete_24); @@ -16181,7 +17490,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.baseline_delete_24); } else { if (currentEncryptedChat == null) { - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { items.add(LocaleController.getString("MessageScheduleSend", R.string.MessageScheduleSend)); options.add(100); icons.add(R.drawable.deproko_baseline_send_24); @@ -16207,7 +17516,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(3); icons.add(R.drawable.baseline_content_copy_24); } - if (!isThreadChat() && !inScheduleMode && currentChat != null && currentChat.has_link && currentChat.megagroup && message.canViewThread()) { + if (!isThreadChat() && chatMode != MODE_SCHEDULED && currentChat != null && (currentChat.has_link || message.hasReplies()) && currentChat.megagroup && message.canViewThread()) { if (message.hasReplies()) { items.add(LocaleController.formatPluralString("ViewReplies", message.getRepliesCount())); } else { @@ -16216,13 +17525,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(27); icons.add(R.drawable.msg_viewreplies); } - if (!inScheduleMode && ChatObject.isChannel(currentChat) && selectedObject.getDialogId() != mergeDialogId) { + if (chatMode != MODE_SCHEDULED && ChatObject.isChannel(currentChat) && selectedObject.getDialogId() != mergeDialogId) { items.add(LocaleController.getString("CopyLink", R.string.CopyLink)); options.add(22); icons.add(R.drawable.baseline_link_24); } if (type == 2) { - if (!inScheduleMode) { + if (chatMode != MODE_SCHEDULED) { if (selectedObject.type == MessageObject.TYPE_POLL && !message.isPollClosed()) { if (message.canUnvote()) { items.add(LocaleController.getString("Unvote", R.string.Unvote)); @@ -16240,6 +17549,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(26); icons.add(R.drawable.msg_pollstop); } + } else if (selectedObject.isMusic()) { + items.add(LocaleController.getString("SaveToMusic", R.string.SaveToMusic)); + options.add(10); + icons.add(R.drawable.msg_download); + } else if (selectedObject.isDocument()) { + items.add(LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + options.add(10); + icons.add(R.drawable.msg_download); } } } else if (type == 3) { @@ -16415,7 +17732,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.baseline_star_24); } } - if (!inScheduleMode && !selectedObject.needDrawBluredPreview() && !selectedObject.isLiveLocation() && selectedObject.type != 16) { + if (chatMode != MODE_SCHEDULED && !selectedObject.needDrawBluredPreview() && !selectedObject.isLiveLocation() && selectedObject.type != 16) { items.add(LocaleController.getString("Forward", R.string.Forward)); options.add(2); icons.add(R.drawable.msg_forward); @@ -16425,7 +17742,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(95); icons.add(R.drawable.msg_forward_noquote); } - if (!inScheduleMode && !selectedObject.needDrawBluredPreview() && !selectedObject.isLiveLocation() && selectedObject.type != 16) { + if (chatMode != MODE_SCHEDULED) { if (!UserObject.isUserSelf(currentUser) && NekoConfig.showAddToSavedMessages) { items.add(LocaleController.getString("AddToSavedMessages", R.string.AddToSavedMessages)); options.add(93); @@ -16439,7 +17756,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not icons.add(R.drawable.msg_repeat); } } - if (!inScheduleMode) { + if (chatMode != MODE_SCHEDULED) { boolean allowPrpr = currentUser != null || (currentChat != null && ChatObject.canSendMessages(currentChat) && !currentChat.broadcast && message.isFromUser()); @@ -16491,6 +17808,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(89); icons.add(R.drawable.menu_info); } +// if (message.messageOwner.forwards > 0 && (BuildVars.DEBUG_PRIVATE_VERSION || ChatObject.hasAdminRights(getCurrentChat()))) { +// items.add(LocaleController.getString("ViewStats", R.string.ViewStats)); +// options.add(28); +// icons.add(R.drawable.msg_stats); +// } if (allowUnpin) { items.add(LocaleController.getString("UnpinMessage", R.string.UnpinMessage)); options.add(14); @@ -16505,12 +17827,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(12); icons.add(R.drawable.baseline_edit_24); } - if (inScheduleMode && selectedObject.canEditMessageScheduleTime(currentChat)) { + if (chatMode == MODE_SCHEDULED && selectedObject.canEditMessageScheduleTime(currentChat)) { items.add(LocaleController.getString("MessageScheduleEditTime", R.string.MessageScheduleEditTime)); options.add(102); icons.add(R.drawable.baseline_date_range_24); } - if (!inScheduleMode && selectedObject.contentType == 0 && selectedObject.getId() > 0 && !selectedObject.isOut() && (currentChat != null || currentUser != null && currentUser.bot)) { + if (chatMode != MODE_SCHEDULED && selectedObject.contentType == 0 && selectedObject.getId() > 0 && !selectedObject.isOut() && (currentChat != null || currentUser != null && currentUser.bot)) { if (UserObject.isReplyUser(currentUser)) { items.add(LocaleController.getString("BlockContact", R.string.BlockContact)); } else { @@ -16519,7 +17841,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(23); icons.add(R.drawable.baseline_report_24); } - if (message.canDeleteMessage(inScheduleMode, currentChat) && (threadMessageObjects == null || !threadMessageObjects.contains(message))) { + if (message.canDeleteMessage(chatMode == MODE_SCHEDULED, currentChat) && (threadMessageObjects == null || !threadMessageObjects.contains(message))) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); icons.add(R.drawable.baseline_delete_24); @@ -16535,7 +17857,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not options.add(3); icons.add(R.drawable.baseline_content_copy_24); } - if (!isThreadChat() && !inScheduleMode && currentChat != null && currentChat.has_link && currentChat.megagroup && message.canViewThread()) { + if (!isThreadChat() && chatMode != MODE_SCHEDULED && currentChat != null && (currentChat.has_link || message.hasReplies()) && currentChat.megagroup && message.canViewThread()) { if (message.hasReplies()) { items.add(LocaleController.formatPluralString("ViewReplies", message.getRepliesCount())); } else { @@ -16721,7 +18043,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not linearLayout.addView(cell); final int i = a; cell.setOnClickListener(v1 -> { - if (selectedObject == null || i < 0 || i >= options.size()) { + if (selectedObject == null || i >= options.size()) { return; } processSelectedOption(options.get(i)); @@ -16788,6 +18110,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }; + scrimPopupWindow.setPauseNotifications(true); scrimPopupWindow.setDismissAnimationDuration(220); scrimPopupWindow.setOutsideTouchable(true); scrimPopupWindow.setClippingEnabled(true); @@ -16858,6 +18181,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (topUndoView != null) { topUndoView.hide(true, 1); } + if (undoView != null) { + undoView.hide(true, 1); + } if (chatActivityEnterView != null) { chatActivityEnterView.getEditField().setAllowDrawCursor(false); } @@ -16923,6 +18249,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not addToSelectedMessages(message, listView); + if (chatActivityEnterView != null) { + chatActivityEnterView.preventInput = true; + } + selectedMessagesCountTextView.setNumber(selectedMessagesIds[0].size() + selectedMessagesIds[1].size(), false); updateVisibleRows(); } @@ -16981,12 +18311,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void restartSticker(ChatMessageCell cell) { MessageObject message = cell.getMessageObject(); TLRPC.Document document = message.getDocument(); - if (message.isAnimatedEmoji() || MessageObject.isAnimatedStickerDocument(document, currentEncryptedChat == null || message.isOut()) && !SharedConfig.loopStickers) { + boolean isEmoji; + if ((isEmoji = message.isAnimatedEmoji()) || MessageObject.isAnimatedStickerDocument(document, currentEncryptedChat == null || message.isOut()) && !SharedConfig.loopStickers) { ImageReceiver imageReceiver = cell.getPhotoImage(); RLottieDrawable drawable = imageReceiver.getLottieAnimation(); if (drawable != null) { - drawable.restart(); - if (message.isAnimatedEmoji()) { + if (isEmoji) { String emoji = message.getStickerEmoji(); if (EmojiData.isHeartEmoji(emoji)) { HashMap pattern = new HashMap<>(); @@ -17001,8 +18331,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not HashMap pattern = new HashMap<>(); pattern.put(34, 1); drawable.setVibrationPattern(pattern); + } else if (EmojiData.isCofinEmoji(emoji)) { + HashMap pattern = new HashMap<>(); + pattern.put(24, 0); + pattern.put(36, 0); + drawable.setVibrationPattern(pattern); + } + if (!drawable.isRunning() && emoji != null) { + MessagesController.EmojiSound sound = getMessagesController().emojiSounds.get(emoji.replace("\uFE0F", "")); + if (sound != null) { + getMediaController().playEmojiSound(getAccountInstance(), emoji, sound, false); + } } } + drawable.restart(); } } } @@ -17035,6 +18377,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return str; } + private void unpinMessage(MessageObject messageObject) { + if (messageObject == null) { + return; + } + ArrayList objects = new ArrayList<>(); + objects.add(selectedObject); + ArrayList ids = new ArrayList<>(); + ids.add(messageObject.getId()); + int oldTotalPinnedCount = totalPinnedMessagesCount; + getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialog_id, ids, false, null, null, 0, totalPinnedMessagesCount - 1, pinnedEndReached); + pinBulletin = BulletinFactory.createUnpinMessageBulletin(this, + () -> { + getNotificationCenter().postNotificationName(NotificationCenter.didLoadPinnedMessages, dialog_id, ids, true, objects, null, 0, oldTotalPinnedCount, pinnedEndReached); + pinBulletin = null; + }, + () -> { + getMessagesController().pinMessage(currentChat, currentUser, messageObject.getId(), true, false, false); + pinBulletin = null; + }).show(); + } + private void saveMessageToGallery(MessageObject messageObject) { String path = messageObject.messageOwner.attachPath; if (!TextUtils.isEmpty(path)) { @@ -17100,13 +18463,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not success = false; } } - if (success && !inScheduleMode) { + if (success && chatMode == 0) { moveScrollToLastMessage(); } } else { if (getSendMessagesHelper().retrySendMessage(selectedObject, false)) { updateVisibleRows(); - if (!inScheduleMode) { + if (chatMode == 0) { moveScrollToLastMessage(); } } @@ -17159,11 +18522,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } if (selectedObjectGroup != null) { - for (int a = 0; a < selectedObjectGroup.messages.size(); a++) { - saveMessageToGallery(selectedObjectGroup.messages.get(a)); + int filesAmount = selectedObjectGroup.messages.size(); + boolean allPhotos = true, allVideos = true; + for (int a = 0; a < filesAmount; a++) { + MessageObject messageObject = selectedObjectGroup.messages.get(a); + saveMessageToGallery(messageObject); + allPhotos &= messageObject.isPhoto(); + allVideos &= messageObject.isVideo(); } + final BulletinFactory.FileType fileType; + if (allPhotos) { + fileType = BulletinFactory.FileType.PHOTOS; + } else if (allVideos) { + fileType = BulletinFactory.FileType.VIDEOS; + } else { + fileType = BulletinFactory.FileType.MEDIA; + } + BulletinFactory.of(this).createDownloadBulletin(fileType, filesAmount).show(); } else { saveMessageToGallery(selectedObject); + BulletinFactory.createSaveToGalleryBulletin(this, selectedObject.isVideo()).show(); } break; } @@ -17293,6 +18671,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } MediaController.saveFile(path, getParentActivity(), 0, null, null); + BulletinFactory.createSaveToGalleryBulletin(this, selectedObject.isVideo()).show(); break; } case 8: { @@ -17313,21 +18692,53 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedObjectToEditCaption = null; return; } - String fileName = FileLoader.getDocumentFileName(selectedObject.getDocument()); - if (TextUtils.isEmpty(fileName)) { - fileName = selectedObject.getFileName(); - } - String path = selectedObject.messageOwner.attachPath; - if (path != null && path.length() > 0) { - File temp = new File(path); - if (!temp.exists()) { - path = null; + boolean isMusic = selectedObject.isMusic(); + boolean isDocument = selectedObject.isDocument(); + if (isMusic || isDocument) { + ArrayList messageObjects; + if (selectedObjectGroup != null) { + messageObjects = new ArrayList<>(selectedObjectGroup.messages); + } else { + messageObjects = new ArrayList<>(); + messageObjects.add(selectedObject); } + MediaController.saveFilesFromMessages(getParentActivity(), getAccountInstance(), messageObjects, (count) -> { + if (count > 0) { + BulletinFactory.of(this).createDownloadBulletin(isMusic ? BulletinFactory.FileType.AUDIOS : BulletinFactory.FileType.UNKNOWNS, count).show(); + } + }); + } else { + boolean video = selectedObject.isVideo(); + boolean photo = selectedObject.isPhoto(); + boolean gif = selectedObject.isGif(); + String fileName = FileLoader.getDocumentFileName(selectedObject.getDocument()); + if (TextUtils.isEmpty(fileName)) { + fileName = selectedObject.getFileName(); + } + 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(); + } + MediaController.saveFile(path, getParentActivity(), 2, fileName, selectedObject.getDocument() != null ? selectedObject.getDocument().mime_type : "", () -> { + final BulletinFactory.FileType fileType; + if (photo) { + fileType = BulletinFactory.FileType.PHOTO_TO_DOWNLOADS; + } else if (video) { + fileType = BulletinFactory.FileType.VIDEO_TO_DOWNLOADS; + } else if (gif) { + fileType = BulletinFactory.FileType.GIF; + } else { + fileType = BulletinFactory.FileType.UNKNOWN; + } + BulletinFactory.of(this).createDownloadBulletin(fileType).show(); + }); } - if (path == null || path.length() == 0) { - path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); - } - MediaController.saveFile(path, getParentActivity(), selectedObject.isMusic() ? 3 : 2, fileName, selectedObject.getDocument() != null ? selectedObject.getDocument().mime_type : ""); break; } case 11: { @@ -17349,45 +18760,88 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not break; } case 13: { - final int mid = selectedObject.getId(); + final int mid; + if (selectedObjectGroup != null && !selectedObjectGroup.messages.isEmpty()) { + mid = selectedObjectGroup.messages.get(0).getId(); + } else { + mid = selectedObject.getId(); + } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("PinMessageAlertTitle", R.string.PinMessageAlertTitle)); final boolean[] checks; if (currentUser != null) { - builder.setMessage(LocaleController.getString("PinMessageAlertChat", R.string.PinMessageAlertChat)); - checks = new boolean[]{false}; + if (currentPinnedMessageId != 0 && mid < currentPinnedMessageId) { + builder.setMessage(LocaleController.getString("PinOldMessageAlert", R.string.PinOldMessageAlert)); + } else { + builder.setMessage(LocaleController.getString("PinMessageAlertChat", R.string.PinMessageAlertChat)); + } + checks = new boolean[]{false, false}; + if (!UserObject.isUserSelf(currentUser)) { + FrameLayout frameLayout = new FrameLayout(getParentActivity()); + CheckBoxCell cell = new CheckBoxCell(getParentActivity(), 1); + cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + cell.setText(LocaleController.formatString("PinAlsoFor", R.string.PinAlsoFor, UserObject.getFirstName(currentUser)), "", false, false); + cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); + frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 0, 8, 0)); + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + checks[1] = !checks[1]; + cell1.setChecked(checks[1], true); + }); + builder.setView(frameLayout); + } } else if (ChatObject.isChannel(currentChat) && currentChat.megagroup || currentChat != null && !ChatObject.isChannel(currentChat)) { - builder.setMessage(LocaleController.getString("PinMessageAlert", R.string.PinMessageAlert)); - checks = new boolean[]{true}; - FrameLayout frameLayout = new FrameLayout(getParentActivity()); - CheckBoxCell cell = new CheckBoxCell(getParentActivity(), 1); - cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); - cell.setText(LocaleController.formatString("PinNotify", R.string.PinNotify), "", true, false); - cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); - frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 0, 8, 0)); - cell.setOnClickListener(v -> { - CheckBoxCell cell1 = (CheckBoxCell) v; - checks[0] = !checks[0]; - cell1.setChecked(checks[0], true); - }); - builder.setView(frameLayout); + if (!pinnedMessageIds.isEmpty() && mid < pinnedMessageIds.get(0)) { + builder.setMessage(LocaleController.getString("PinOldMessageAlert", R.string.PinOldMessageAlert)); + checks = new boolean[]{false, true}; + } else { + builder.setMessage(LocaleController.getString("PinMessageAlert", R.string.PinMessageAlert)); + checks = new boolean[]{true, true}; + FrameLayout frameLayout = new FrameLayout(getParentActivity()); + CheckBoxCell cell = new CheckBoxCell(getParentActivity(), 1); + cell.setBackgroundDrawable(Theme.getSelectorDrawable(false)); + cell.setText(LocaleController.getString("PinNotify", R.string.PinNotify), "", true, false); + cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); + frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 0, 8, 0)); + cell.setOnClickListener(v -> { + CheckBoxCell cell1 = (CheckBoxCell) v; + checks[0] = !checks[0]; + cell1.setChecked(checks[0], true); + }); + builder.setView(frameLayout); + } } else { - builder.setMessage(LocaleController.getString("PinMessageAlertChannel", R.string.PinMessageAlertChannel)); - checks = new boolean[]{false}; + if (currentPinnedMessageId != 0 && mid < currentPinnedMessageId) { + builder.setMessage(LocaleController.getString("PinOldMessageAlert", R.string.PinOldMessageAlert)); + } else { + builder.setMessage(LocaleController.getString("PinMessageAlertChannel", R.string.PinMessageAlertChannel)); + } + checks = new boolean[]{false, true}; } - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, mid, checks[0])); + builder.setPositiveButton(LocaleController.getString("PinMessage", R.string.PinMessage), (dialogInterface, i) -> { + getMessagesController().pinMessage(currentChat, currentUser, mid, false, !checks[1], checks[0]); + BulletinFactory.createPinMessageBulletin(this).show(); + }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); break; } case 14: { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("UnpinMessageAlertTitle", R.string.UnpinMessageAlertTitle)); - builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); - builder.setPositiveButton(LocaleController.getString("UnpinMessage", R.string.UnpinMessage), (dialogInterface, i) -> getMessagesController().pinMessage(currentChat, currentUser, 0, false)); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + MessageObject messageObject; + if (pinnedMessageObjects.containsKey(selectedObject.getId())) { + messageObject = selectedObject; + } else if (selectedObjectGroup != null && !selectedObjectGroup.messages.isEmpty()) { + messageObject = selectedObjectGroup.messages.get(0); + } else { + messageObject = selectedObject; + } + if (chatMode == MODE_PINNED && messages.size() == 2) { + finishFragment(); + chatActivityDelegate.onUnpin(false, false); + } else { + unpinMessage(messageObject); + } break; } case 15: { @@ -17588,7 +19042,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } case 90: { TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(selectedObject.messageOwner.from_id.user_id); - getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, 0, user); + getMediaDataController().searchMessagesInChat("", dialog_id, mergeDialogId, classGuid, 0, 0, user, null); showMessagesSearchListView(true); break; } @@ -17678,6 +19132,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openDiscussionMessageChat(currentChat.id, null, selectedObject.getId(), 0, -1, 0, null); break; } + case 28: { + presentFragment(new MessageStatisticActivity(selectedObject)); + break; + } case 100: { if (!checkSlowMode(chatActivityEnterView.getSendButton())) { if (getMediaController().isPlayingMessage(selectedObject)) { @@ -17898,7 +19356,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not fragment.finishFragment(); } else { long did = dids.get(0); - if (did != dialog_id) { + if (did != dialog_id || chatMode == MODE_PINNED) { int lower_part = (int) did; int high_part = (int) (did >> 32); Bundle args = new Bundle(); @@ -17909,7 +19367,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { args.putInt("chat_id", -lower_part); } } else { @@ -18003,7 +19461,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public void onListItemAniamtorTick() { - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); if (scrimView != null) { fragmentView.invalidate(); } @@ -18195,7 +19653,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (text != null) { searchItem.setSearchFieldText(text, false); - getMediaDataController().searchMessagesInChat(text, dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages); + getMediaDataController().searchMessagesInChat(text, dialog_id, mergeDialogId, classGuid, 0, threadMessageId, searchingUserMessages, searchingChatMessages); } updatePinnedMessageView(true); } @@ -18203,7 +19661,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void didSelectLocation(TLRPC.MessageMedia location, int locationType, boolean notify, int scheduleDate) { getSendMessagesHelper().sendMessage(location, dialog_id, replyingMessageObject, getThreadMessage(), null, null, notify, scheduleDate); - if (!inScheduleMode) { + if (chatMode == 0) { moveScrollToLastMessage(); } if (locationType == LocationActivity.LOCATION_TYPE_SEND || locationType == LocationActivity.LOCATION_TYPE_SEND_WITH_LIVE) { @@ -18227,7 +19685,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } public boolean isInScheduleMode() { - return inScheduleMode; + return chatMode == MODE_SCHEDULED; + } + + public int getChatMode() { + return chatMode; } public MessageObject getThreadMessage() { @@ -18296,10 +19758,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not afterMessageSend(); } else { if (photoEntry.imagePath != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, null, dialog_id, replyingMessageObject, getThreadMessage(), photoEntry.caption, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, notify, scheduleDate); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.imagePath, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), photoEntry.caption, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate); afterMessageSend(); } else if (photoEntry.path != null) { - SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, null, dialog_id, replyingMessageObject, getThreadMessage(), photoEntry.caption, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, notify, scheduleDate); + SendMessagesHelper.prepareSendingPhoto(getAccountInstance(), photoEntry.path, photoEntry.thumbPath, null, dialog_id, replyingMessageObject, getThreadMessage(), photoEntry.caption, photoEntry.entities, photoEntry.stickers, null, photoEntry.ttl, editingMessageObject, videoEditedInfo, notify, scheduleDate); afterMessageSend(); } } @@ -18393,7 +19855,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } TLRPC.messages_Messages historyFinal = history; int fnidFinal = fnid; - Utilities.stageQueue.postRunnable(() -> getMessagesController().processLoadedMessages(historyFinal, dialogId, 0, 30, maxReadId, 0, false, chatActivity.getClassGuid(), fnidFinal, 0, 0, 0, 2, true, false, false, arrayList.get(arrayList.size() - 1).getId(), 1, false, 0)); + Utilities.stageQueue.postRunnable(() -> getMessagesController().processLoadedMessages(historyFinal, dialogId, 0, 30, maxReadId, 0, false, chatActivity.getClassGuid(), fnidFinal, 0, 0, 0, 2, true, false, 0, arrayList.get(arrayList.size() - 1).getId(), 1, false, 0)); } } @@ -18441,50 +19903,60 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }; if (maxReadId >= 0 && linkedChatId != 0) { - int count = 30; TLRPC.Chat linkedChat = getMessagesController().getChat(linkedChatId); - TLRPC.TL_messages_getReplies getReplies = new TLRPC.TL_messages_getReplies(); - getReplies.peer = MessagesController.getInputPeer(linkedChat); - getReplies.msg_id = maxReadId; - getReplies.offset_date = 0; - getReplies.add_offset = -count + 10; - getReplies.limit = count; - getReplies.offset_id = maxReadId; - int guid = ++commentMessagesLoadingGuid; - commentMessagesRequestId = getConnectionsManager().sendRequest(getReplies, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (guid != commentMessagesLoadingGuid) { - return; - } - commentMessagesRequestId = -1; - if (response != null) { - savedHistory = (TLRPC.messages_Messages) response; - if (savedHistory.messages.size() > count) { - savedHistory.messages.remove(0); - } - } else { - savedNoHistory = true; - } - processLoadedDiscussionMessage(savedNoDiscussion, savedDiscussionMessage, savedNoHistory, savedHistory, maxReadId, fallbackMessage, progressRunnable, req, chat, highlightMsgId, originalMessage); - })); - getConnectionsManager().bindRequestToGuid(commentMessagesRequestId, classGuid); + if (linkedChat != null) { + int count = 30; + TLRPC.TL_messages_getReplies getReplies = new TLRPC.TL_messages_getReplies(); + getReplies.peer = MessagesController.getInputPeer(linkedChat); + getReplies.msg_id = maxReadId; + getReplies.offset_date = 0; + getReplies.add_offset = -count + 10; + getReplies.limit = count; + getReplies.offset_id = maxReadId; + int guid = ++commentMessagesLoadingGuid; + commentMessagesRequestId = getConnectionsManager().sendRequest(getReplies, (response, error) -> { + Runnable runnable = () -> { + if (guid != commentMessagesLoadingGuid) { + return; + } + commentMessagesRequestId = -1; + if (response != null) { + savedHistory = (TLRPC.messages_Messages) response; + if (savedHistory.messages.size() > count) { + savedHistory.messages.remove(0); + } + } else { + savedNoHistory = true; + } + processLoadedDiscussionMessage(savedNoDiscussion, savedDiscussionMessage, savedNoHistory, savedHistory, maxReadId, fallbackMessage, progressRunnable, req, chat, highlightMsgId, originalMessage); + }; + AndroidUtilities.runOnUIThread(() -> doOnIdle(runnable)); + }); + getConnectionsManager().bindRequestToGuid(commentMessagesRequestId, classGuid); + } else { + savedNoHistory = true; + } } else { savedNoHistory = true; } int guid = ++commentLoadingGuid; - commentRequestId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (guid != commentLoadingGuid) { - return; - } - commentRequestId = -1; - if (response instanceof TLRPC.TL_messages_discussionMessage) { - savedDiscussionMessage = (TLRPC.TL_messages_discussionMessage) response; - getMessagesController().putUsers(savedDiscussionMessage.users, false); - getMessagesController().putChats(savedDiscussionMessage.chats, false); - } else { - savedNoDiscussion = true; - } - processLoadedDiscussionMessage(savedNoDiscussion, savedDiscussionMessage, savedNoHistory, savedHistory, maxReadId, fallbackMessage, progressRunnable, req, chat, highlightMsgId, originalMessage); - })); + commentRequestId = getConnectionsManager().sendRequest(req, (response, error) -> { + Runnable runnable = () -> { + if (guid != commentLoadingGuid) { + return; + } + commentRequestId = -1; + if (response instanceof TLRPC.TL_messages_discussionMessage) { + savedDiscussionMessage = (TLRPC.TL_messages_discussionMessage) response; + getMessagesController().putUsers(savedDiscussionMessage.users, false); + getMessagesController().putChats(savedDiscussionMessage.chats, false); + } else { + savedNoDiscussion = true; + } + processLoadedDiscussionMessage(savedNoDiscussion, savedDiscussionMessage, savedNoHistory, savedHistory, maxReadId, fallbackMessage, progressRunnable, req, chat, highlightMsgId, originalMessage); + }; + AndroidUtilities.runOnUIThread(() -> doOnIdle(runnable)); + }); getConnectionsManager().bindRequestToGuid(commentRequestId, classGuid); AndroidUtilities.runOnUIThread(progressRunnable, 500); } @@ -18536,7 +20008,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stringBuilder.setSpan(new URLSpan(""), index, index + request.domain.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } cells[a].setText(stringBuilder, "", true, false); - } else if (a == 1) { + } else { cells[a].setText(AndroidUtilities.replaceTags(LocaleController.formatString("OpenUrlOption2", R.string.OpenUrlOption2, UserObject.getFirstName(request.bot))), "", true, false); } cells[a].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); @@ -18665,7 +20137,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (str.startsWith("#") || str.startsWith("$")) { if (ChatObject.isChannel(currentChat)) { - if (inScheduleMode) { + if (chatMode == MODE_SCHEDULED) { chatActivityDelegate.openSearch(str); finishFragment(); } else { @@ -18896,7 +20368,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } MediaController.getInstance().cleanupPlayer(true, true, false, playingObject.equals(message)); } - if (inScheduleMode && (message.isVideo() || message.type == 1)) { + if (chatMode == MODE_SCHEDULED && (message.isVideo() || message.type == 1)) { PhotoViewer.getInstance().setParentChatActivity(ChatActivity.this); ArrayList arrayList = new ArrayList<>(); for (int a = 0, N = messages.size(); a < N; a++) { @@ -18976,7 +20448,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not rowCount += messages.size(); messagesEndRow = rowCount; - if (currentUser != null && currentUser.bot && !inScheduleMode && (botInfo.size() > 0 && botInfo.get(currentUser.id).description != null || UserObject.isReplyUser(currentUser)) && endReached[0]) { + if (currentUser != null && currentUser.bot && chatMode == 0 && (botInfo.size() > 0 && botInfo.get(currentUser.id).description != null || UserObject.isReplyUser(currentUser)) && endReached[0]) { botInfoRow = rowCount++; } else { botInfoRow = -5; @@ -18993,7 +20465,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messagesStartRow = -5; messagesEndRow = -5; - if (UserObject.isReplyUser(currentUser) || currentUser != null && currentUser.bot && !MessagesController.isSupportUser(currentUser) && !inScheduleMode) { + if (UserObject.isReplyUser(currentUser) || currentUser != null && currentUser.bot && !MessagesController.isSupportUser(currentUser) && chatMode == 0) { botInfoRow = rowCount++; } else { botInfoRow = -5; @@ -19102,7 +20574,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.closeKeyboard(); } MessageObject messageObject = cell.getMessageObject(); - if ((UserObject.isReplyUser(currentUser) || UserObject.isUserSelf(currentUser)) && messageObject.messageOwner.fwd_from.saved_from_peer != null) { + if (chatMode == MODE_PINNED) { + chatActivityDelegate.openReplyMessage(messageObject.getId()); + finishFragment(); + } else if ((UserObject.isReplyUser(currentUser) || UserObject.isUserSelf(currentUser)) && messageObject.messageOwner.fwd_from.saved_from_peer != null) { if (UserObject.isReplyUser(currentUser) && messageObject.messageOwner.reply_to != null && messageObject.messageOwner.reply_to.reply_to_top_id != 0) { openDiscussionMessageChat(messageObject.messageOwner.reply_to.reply_to_peer_id.channel_id, null, messageObject.messageOwner.reply_to.reply_to_top_id, 0, -1, messageObject.messageOwner.fwd_from.saved_from_msg_id, messageObject); } else { @@ -19177,7 +20652,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not VoIPHelper.startCall(currentUser, messageObject.isVideoCall(), userInfo != null && userInfo.video_calls_available, getParentActivity(), getMessagesController().getUserFull(currentUser.id)); } } else { - createMenu(cell, true, false, otherX, otherY, false); + createMenu(cell, true, false, otherX, otherY, messageObject.isMusic()); } } @@ -19368,7 +20843,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not float lastDiff = 0; for (int a = 0, N = pollButtons.size(); a < N; a++) { ChatMessageCell.PollButton button = pollButtons.get(a); - lastDiff = cell.getY() + button.y - AndroidUtilities.dp(4) - chatListView.getPaddingTop(); + lastDiff = cell.getY() + button.y - AndroidUtilities.dp(4) - chatListViewPaddingTop; pollHintX = button.x + AndroidUtilities.dp(13.3f); pollHintY = button.y - AndroidUtilities.dp(6) + y; if (lastDiff > 0) { @@ -19429,7 +20904,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } MessageObject messageObject = cell.getMessageObject(); - if (inScheduleMode) { + if (chatMode == MODE_PINNED || chatMode == MODE_SCHEDULED) { chatActivityDelegate.openReplyMessage(id); finishFragment(); } else { @@ -19457,7 +20932,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void needReloadPolls() { - updateMessagesVisiblePart(false); + invalidateMessagesVisiblePart(); } @Override @@ -19511,19 +20986,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (!AndroidUtilities.isGoogleMapsInstalled(ChatActivity.this)) { return; } - if (message.isLiveLocation()) { - LocationActivity fragment = new LocationActivity(2); + /*if (message.isLiveLocation()) { + LocationActivity fragment = new LocationActivity(currentChat == null || ChatObject.canSendMessages(currentChat) || currentChat.megagroup ? 2 : LocationActivity.LOCATION_TYPE_LIVE_VIEW); fragment.setDelegate(ChatActivity.this); fragment.setMessageObject(message); - fragment.setDelegate(ChatActivity.this); presentFragment(fragment); - } else { + } else {*/ LocationActivity fragment = new LocationActivity(currentEncryptedChat == null ? 3 : 0); fragment.setDelegate(ChatActivity.this); fragment.setMessageObject(message); - fragment.setDelegate(ChatActivity.this); presentFragment(fragment); - } + //} } else if (message.type == 9 || message.type == 0) { File locFile = null; if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { @@ -19804,38 +21277,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (view instanceof ChatMessageCell) { final ChatMessageCell messageCell = (ChatMessageCell) view; + MessageObject.GroupedMessages groupedMessages = getValidGroupedMessage(message); messageCell.isChat = currentChat != null || UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser); messageCell.isBot = currentUser != null && currentUser.bot; messageCell.isMegagroup = ChatObject.isChannel(currentChat) && currentChat.megagroup; messageCell.isThreadChat = threadMessageId != 0; - messageCell.hasDiscussion = !inScheduleMode && ChatObject.isChannel(currentChat) && currentChat.has_link && !currentChat.megagroup; - messageCell.linkedChatId = !inScheduleMode && chatInfo != null ? chatInfo.linked_chat_id : 0; - messageCell.hasLinkedChat = !inScheduleMode && currentChat != null && currentChat.has_link; + messageCell.hasDiscussion = chatMode != MODE_SCHEDULED && ChatObject.isChannel(currentChat) && currentChat.has_link && !currentChat.megagroup; + messageCell.isPinned = chatMode == 0 && (pinnedMessageObjects.containsKey(message.getId()) || groupedMessages != null && !groupedMessages.messages.isEmpty() && pinnedMessageObjects.containsKey(groupedMessages.messages.get(0).getId())); + messageCell.linkedChatId = chatMode != MODE_SCHEDULED && chatInfo != null ? chatInfo.linked_chat_id : 0; messageCell.isRepliesChat = UserObject.isReplyUser(currentUser); + messageCell.isPinnedChat = chatMode == MODE_PINNED; boolean pinnedBottom = false; boolean pinnedBottomByGroup = false; boolean pinnedTop = false; boolean pinnedTopByGroup = false; - MessageObject.GroupedMessages groupedMessages = getValidGroupedMessage(message); int prevPosition; int nextPosition; if (groupedMessages != null) { MessageObject.GroupedMessagePosition pos = groupedMessages.positions.get(message); if (pos != null) { - if ((pos.flags & MessageObject.POSITION_FLAG_TOP) != 0) { + if (groupedMessages.isDocuments) { prevPosition = position + groupedMessages.posArray.indexOf(pos) + 1; - } else { - pinnedTop = true; - pinnedTopByGroup = true; - prevPosition = -100; - } - if ((pos.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { nextPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); } else { - pinnedBottom = true; - pinnedBottomByGroup = true; - nextPosition = -100; + if ((pos.flags & MessageObject.POSITION_FLAG_TOP) != 0) { + prevPosition = position + groupedMessages.posArray.indexOf(pos) + 1; + } else { + pinnedTop = true; + pinnedTopByGroup = true; + prevPosition = -100; + } + if ((pos.flags & MessageObject.POSITION_FLAG_BOTTOM) != 0) { + nextPosition = position - groupedMessages.posArray.size() + groupedMessages.posArray.indexOf(pos); + } else { + pinnedBottom = true; + pinnedBottomByGroup = true; + nextPosition = -100; + } } } else { prevPosition = -100; @@ -19847,6 +21326,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } int nextType = getItemViewType(nextPosition); int prevType = getItemViewType(prevPosition); + if (!message.hasReactions() && !(message.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) && nextType == holder.getItemViewType()) { MessageObject nextMessage = messages.get(nextPosition - messagesStartRow); pinnedBottom = nextMessage.isOutOwner() == message.isOutOwner() && Math.abs(nextMessage.messageOwner.date - message.messageOwner.date) <= 5 * 60; @@ -19854,7 +21334,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat != null) { int fromId = nextMessage.getFromChatId(); pinnedBottom = fromId == message.getFromChatId(); - if (pinnedBottom && fromId < 0 && currentChat.megagroup) { + if (!pinnedBottomByGroup && pinnedBottom && fromId < 0 && currentChat.megagroup) { pinnedBottom = false; } } else if (UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser)) { @@ -19873,7 +21353,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (currentChat != null) { int fromId = prevMessage.getFromChatId(); pinnedTop = fromId == message.getFromChatId(); - if (pinnedTop && fromId < 0 && currentChat.megagroup) { + if (!pinnedTopByGroup && pinnedTop && fromId < 0 && currentChat.megagroup) { pinnedTop = false; } } else if (UserObject.isUserSelf(currentUser) || UserObject.isReplyUser(currentUser)) { @@ -20029,6 +21509,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (hintMessageObject != null && hintMessageObject.equals(message)) { messageCell.showHintButton(false, false, hintMessageType); } + if (message.isAnimatedEmoji()) { + String emoji = message.getStickerEmoji(); + if (emoji != null) { + MessagesController.EmojiSound sound = getMessagesController().emojiSounds.get(emoji.replace("\uFE0F", "")); + if (sound != null) { + getMediaController().playEmojiSound(getAccountInstance(), emoji, sound, true); + } + } + } boolean selected = false; boolean disableSelection = false; @@ -20091,7 +21580,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MessageObject message = messages.get(position - messagesStartRow); View view = holder.itemView; if (message != null && message.messageOwner != null && message.messageOwner.media_unread && message.messageOwner.mentioned) { - if (!inPreviewMode && !inScheduleMode) { + if (!inPreviewMode && chatMode == 0) { if (!message.isVoice() && !message.isRoundVideo()) { newMentionsCount--; if (newMentionsCount <= 0) { @@ -20143,6 +21632,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + public void invalidateRowWithMessageObject(MessageObject messageObject) { + int count = chatListView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = chatListView.getChildAt(a); + if (child instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) child; + if (cell.getMessageObject() == messageObject) { + cell.invalidate(); + return; + } + } + } + } + public View updateRowWithMessageObject(MessageObject messageObject, boolean allowInPlace) { if (allowInPlace) { int count = chatListView.getChildCount(); @@ -20333,7 +21836,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not openDiscussionMessageChat(currentChat.id, null, threadId, 0, -1, 0, null); } else { showScrollToMessageError = true; - scrollToMessageId(messageId, fromMessageId, true, 0, false); + if (chatMode == MODE_PINNED) { + chatActivityDelegate.openReplyMessage(messageId); + finishFragment(); + } else { + scrollToMessageId(messageId, fromMessageId, true, 0, false); + } } return true; } @@ -20352,7 +21860,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { int messageId = Integer.parseInt(matcher.group(3)); showScrollToMessageError = true; - scrollToMessageId(messageId, fromMessageId, true, 0, false); + if (chatMode == MODE_PINNED) { + chatActivityDelegate.openReplyMessage(messageId); + finishFragment(); + } else { + scrollToMessageId(messageId, fromMessageId, true, 0, false); + } } return true; } else if (urlFinal.startsWith("tg:resolve") || urlFinal.startsWith("tg://resolve")) { @@ -20366,7 +21879,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (threadId != 0 || commentId != 0) { return false; } else { - scrollToMessageId(messageId, fromMessageId, true, 0, false); + if (chatMode == MODE_PINNED) { + chatActivityDelegate.openReplyMessage(messageId); + finishFragment(); + } else { + scrollToMessageId(messageId, fromMessageId, true, 0, false); + } return true; } } @@ -20388,7 +21906,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return false; } else { showScrollToMessageError = true; - scrollToMessageId(messageId, fromMessageId, true, 0, false); + if (chatMode == MODE_PINNED) { + chatActivityDelegate.openReplyMessage(messageId); + finishFragment(); + } else { + scrollToMessageId(messageId, fromMessageId, true, 0, false); + } return true; } } @@ -20433,7 +21956,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateVisibleRows(); - AndroidUtilities.runOnUIThread(() -> getNotificationCenter().onAnimationFinish(animationIndex)); + AndroidUtilities.runOnUIThread(() -> { + if (nextScrollToMessageId != 0) { + scrollToMessageId(nextScrollToMessageId, nextScrollFromMessageId, nextScrollSelect, nextScrollLoadIndex, nextScrollForce); + nextScrollToMessageId = 0; + } + getNotificationCenter().onAnimationFinish(animationIndex); + }); } @Override @@ -20492,6 +22021,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (instantCameraView != null) { instantCameraView.invalidateBlur(); } + + if (pinnedLineView != null) { + pinnedLineView.updateColors(); + } }; ArrayList themeDescriptions = new ArrayList<>(); @@ -20576,13 +22109,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInClockDrawable}, null, Theme.key_chat_inSentClock)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInSelectedClockDrawable}, null, Theme.key_chat_inSentClockSelected)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaCheckDrawable, Theme.chat_msgMediaHalfCheckDrawable}, null, Theme.key_chat_mediaSentCheck)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgStickerHalfCheckDrawable, Theme.chat_msgStickerCheckDrawable, Theme.chat_msgStickerClockDrawable, Theme.chat_msgStickerViewsDrawable, Theme.chat_msgStickerRepliesDrawable}, null, Theme.key_chat_serviceText)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgStickerHalfCheckDrawable, Theme.chat_msgStickerCheckDrawable, Theme.chat_msgStickerClockDrawable, Theme.chat_msgStickerViewsDrawable, Theme.chat_msgStickerRepliesDrawable, Theme.chat_msgStickerPinnedDrawable}, null, Theme.key_chat_serviceText)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaClockDrawable}, null, Theme.key_chat_mediaSentClock)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsDrawable, Theme.chat_msgOutRepliesDrawable}, null, Theme.key_chat_outViews)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsSelectedDrawable, Theme.chat_msgOutRepliesSelectedDrawable}, null, Theme.key_chat_outViewsSelected)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsDrawable, Theme.chat_msgInRepliesDrawable}, null, Theme.key_chat_inViews)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsSelectedDrawable, Theme.chat_msgInRepliesSelectedDrawable}, null, Theme.key_chat_inViewsSelected)); - themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaViewsDrawable, Theme.chat_msgMediaRepliesDrawable}, null, Theme.key_chat_mediaViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsDrawable, Theme.chat_msgOutRepliesDrawable, Theme.chat_msgOutPinnedDrawable}, null, Theme.key_chat_outViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutViewsSelectedDrawable, Theme.chat_msgOutRepliesSelectedDrawable, Theme.chat_msgOutPinnedSelectedDrawable}, null, Theme.key_chat_outViewsSelected)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsDrawable, Theme.chat_msgInRepliesDrawable, Theme.chat_msgInPinnedDrawable}, null, Theme.key_chat_inViews)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInViewsSelectedDrawable, Theme.chat_msgInRepliesSelectedDrawable, Theme.chat_msgInPinnedSelectedDrawable}, null, Theme.key_chat_inViewsSelected)); + themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgMediaViewsDrawable, Theme.chat_msgMediaRepliesDrawable, Theme.chat_msgMediaPinnedDrawable}, null, Theme.key_chat_mediaViews)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutMenuDrawable}, null, Theme.key_chat_outMenu)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgOutMenuSelectedDrawable}, null, Theme.key_chat_outMenuSelected)); themeDescriptions.add(new ThemeDescription(chatListView, 0, new Class[]{ChatMessageCell.class}, null, new Drawable[]{Theme.chat_msgInMenuDrawable}, null, Theme.key_chat_inMenu)); @@ -20865,12 +22398,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND | ThemeDescription.FLAG_CHECKTAG, new Class[]{FragmentContextView.class}, new String[]{"frameLayout"}, null, null, null, Theme.key_returnToCallBackground)); themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, new Class[]{FragmentContextView.class}, new String[]{"titleTextView"}, null, null, null, Theme.key_returnToCallText)); - themeDescriptions.add(new ThemeDescription(pinnedLineView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_chat_topPanelLine)); - themeDescriptions.add(new ThemeDescription(pinnedMessageNameTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelTitle)); - themeDescriptions.add(new ThemeDescription(pinnedMessageTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelMessage)); + themeDescriptions.add(new ThemeDescription(pinnedLineView, 0, null, null, null, selectedBackgroundDelegate, Theme.key_chat_topPanelLine)); + themeDescriptions.add(new ThemeDescription(pinnedLineView, 0, null, null, null, selectedBackgroundDelegate, Theme.key_windowBackgroundWhite)); + themeDescriptions.add(new ThemeDescription(pinnedCounterTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelTitle)); + for (int a = 0; a < 2; a++) { + themeDescriptions.add(new ThemeDescription(pinnedNameTextView[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelTitle)); + themeDescriptions.add(new ThemeDescription(pinnedMessageTextView[a], ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelMessage)); + } themeDescriptions.add(new ThemeDescription(alertNameTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelTitle)); themeDescriptions.add(new ThemeDescription(alertTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_chat_topPanelMessage)); themeDescriptions.add(new ThemeDescription(closePinned, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_chat_topPanelClose)); + themeDescriptions.add(new ThemeDescription(pinnedListButton, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_chat_topPanelTitle)); themeDescriptions.add(new ThemeDescription(closeReportSpam, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_chat_topPanelClose)); themeDescriptions.add(new ThemeDescription(topChatPanelView, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_chat_topPanelBackground)); themeDescriptions.add(new ThemeDescription(alertView, ThemeDescription.FLAG_BACKGROUNDFILTER, null, null, null, null, Theme.key_chat_topPanelBackground)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java index 8d219790f..8bf3a82bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditActivity.java @@ -45,7 +45,6 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.SharedConfig; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -201,7 +200,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image return false; } if (info == null) { - info = MessagesStorage.getInstance(currentAccount).loadChatInfo(chatId, new CountDownLatch(1), false, false); + info = MessagesStorage.getInstance(currentAccount).loadChatInfo(chatId, ChatObject.isChannel(currentChat), new CountDownLatch(1), false, false); if (info == null) { return false; } @@ -1173,7 +1172,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } if (nameTextView != null) { String text = nameTextView.getText().toString(); - if (text != null && text.length() != 0) { + if (text.length() != 0) { args.putString("nameTextView", text); } } @@ -1295,7 +1294,7 @@ public class ChatEditActivity extends BaseFragment implements ImageUpdater.Image } if (stickersCell != null) { - if (info.stickerset != null) { + if (info != null && info.stickerset != null) { stickersCell.setTextAndValue(LocaleController.getString("GroupStickers", R.string.GroupStickers), info.stickerset.title, false); } else { stickersCell.setText(LocaleController.getString("GroupStickers", R.string.GroupStickers), false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 4c96e3a8b..8ee7c0d67 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -126,7 +126,7 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe return false; } if (info == null) { - info = getMessagesStorage().loadChatInfo(chatId, new CountDownLatch(1), false, false); + info = getMessagesStorage().loadChatInfo(chatId, ChatObject.isChannel(currentChat), new CountDownLatch(1), false, false); if (info == null) { return false; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java index eb11433ec..c59f37712 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatLinkActivity.java @@ -407,7 +407,7 @@ public class ChatLinkActivity extends BaseFragment implements NotificationCenter } progressDialog[0] = null; info.linked_chat_id = 0; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false, null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false); AndroidUtilities.runOnUIThread(() -> getMessagesController().loadFullChat(currentChatId, 0, true), 1000); if (!isChannel) { finishFragment(); @@ -537,7 +537,7 @@ public class ChatLinkActivity extends BaseFragment implements NotificationCenter progressDialog[0] = null; } info.linked_chat_id = chat.id; - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false, null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, false); AndroidUtilities.runOnUIThread(() -> getMessagesController().loadFullChat(currentChatId, 0, true), 1000); if (createFragment != null) { removeSelfFromStack(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java index af7457bde..aceca8e14 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatUsersActivity.java @@ -61,6 +61,7 @@ import org.telegram.ui.Cells.TextCheckCell2; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.ManageChatUserCell; import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.EmptyTextProgressView; import org.telegram.ui.Components.IntSeekBarAccessibilityDelegate; import org.telegram.ui.Components.LayoutHelper; @@ -1129,7 +1130,19 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente } private void openRightsEdit2(int userId, int date, TLObject participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean canEditAdmin, int type, boolean removeFragment) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false, participant); + boolean[] needShowBulletin = new boolean[1]; + final boolean isAdmin = participant instanceof TLRPC.TL_channelParticipantAdmin || participant instanceof TLRPC.TL_chatParticipantAdmin; + ChatRightsEditActivity fragment = new ChatRightsEditActivity(userId, chatId, adminRights, defaultBannedRights, bannedRights, rank, type, true, false, participant) { + @Override + protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ChatUsersActivity.this)) { + final TLRPC.User user = getMessagesController().getUser(userId); + if (user != null) { + BulletinFactory.createPromoteToAdminBulletin(ChatUsersActivity.this, user.first_name).show(); + } + } + } + }; fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -1173,6 +1186,9 @@ public class ChatUsersActivity extends BaseFragment implements NotificationCente loadChatParticipants(0, 200); } } + if (rights == 1 && !isAdmin) { + needShowBulletin[0] = true; + } } else if (type == 1) { if (rights == 0) { removeParticipants(userId); 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 2da4c4a51..09d59c2c0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -8,16 +8,20 @@ package org.telegram.ui.Components; +import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.graphics.Color; +import android.graphics.Outline; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.text.Html; import android.text.InputType; @@ -32,6 +36,7 @@ import android.util.TypedValue; import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.View; +import android.view.ViewOutlineProvider; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.FrameLayout; @@ -98,6 +103,8 @@ import tw.nekomimi.nekogram.BottomBuilder; import tw.nekomimi.nekogram.JalaliCalendar; import tw.nekomimi.nekogram.utils.VibrateUtil; +import androidx.annotation.RequiresApi; + public class AlertsCreator { public static Dialog processError(int currentAccount, TLRPC.TL_error error, BaseFragment fragment, TLObject request, Object... args) { @@ -160,7 +167,7 @@ public class AlertsCreator { if (fragment != null) { showSimpleAlert(fragment, LocaleController.getString("EditMessageError", R.string.EditMessageError)); } else { - showSimpleToast(fragment, LocaleController.getString("EditMessageError", R.string.EditMessageError)); + showSimpleToast(null, LocaleController.getString("EditMessageError", R.string.EditMessageError)); } } } else if (request instanceof TLRPC.TL_messages_sendMessage || @@ -219,7 +226,7 @@ public class AlertsCreator { } else if (request instanceof TLRPC.TL_account_sendConfirmPhoneCode) { if (error.code == 400) { return showSimpleAlert(fragment, LocaleController.getString("CancelLinkExpired", R.string.CancelLinkExpired)); - } else if (error.text != null) { + } else { if (error.text.startsWith("FLOOD_WAIT")) { return showSimpleAlert(fragment, LocaleController.getString("FloodWait", R.string.FloodWait)); } else { @@ -265,7 +272,7 @@ public class AlertsCreator { break; } } else if (request instanceof TLRPC.TL_contacts_importContacts) { - if (error == null || error.text.startsWith("FLOOD_WAIT")) { + if (error.text.startsWith("FLOOD_WAIT")) { showSimpleAlert(fragment, LocaleController.getString("FloodWait", R.string.FloodWait)); } else { showSimpleAlert(fragment, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); @@ -437,7 +444,7 @@ public class AlertsCreator { if (!few) { TLRPC.ChatFull chatFull = MessagesController.getInstance(currentAccount).getChatFull(chat.id); if (chatFull == null) { - chatFull = MessagesStorage.getInstance(currentAccount).loadChatInfo(chat.id, new CountDownLatch(1), false, false); + chatFull = MessagesStorage.getInstance(currentAccount).loadChatInfo(chat.id, ChatObject.isChannel(chat), new CountDownLatch(1), false, false); } if (chatFull != null && chatFull.slowmode_next_send_date >= ConnectionsManager.getInstance(currentAccount).getCurrentTime()) { few = true; @@ -578,7 +585,7 @@ public class AlertsCreator { cells[a].setTag(a); if (a == 0) { cells[a].setText(LocaleController.getString("DeleteReportSpam", R.string.DeleteReportSpam), "", true, false); - } else if (a == 1) { + } else { cells[a].setText(LocaleController.formatString("DeleteThisChat", R.string.DeleteThisChat), "", true, false); } cells[a].setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); @@ -1169,7 +1176,7 @@ public class AlertsCreator { avatarDrawable.setInfo(user); imageView.setImage(ImageLocation.getForUser(user, false), "50_50", avatarDrawable, user); } - } else if (chat != null) { + } else { avatarDrawable.setInfo(chat); imageView.setImage(ImageLocation.getForChat(chat, false), "50_50", avatarDrawable, chat); } @@ -1192,7 +1199,7 @@ public class AlertsCreator { messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithUser", R.string.AreYouSureClearHistoryWithUser, UserObject.getUserName(user)))); } } - } else if (chat != null) { + } else { if (!ChatObject.isChannel(chat) || chat.megagroup && TextUtils.isEmpty(chat.username)) { messageTextView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureClearHistoryWithChat", R.string.AreYouSureClearHistoryWithChat, chat.title))); } else if (chat.megagroup) { @@ -2517,7 +2524,48 @@ public class AlertsCreator { return builder.create(); } - public static AlertDialog.Builder createContactsPermissionDialog(final Activity parentActivity, final MessagesStorage.IntCallback callback) { + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public static AlertDialog.Builder createBackgroundLocationPermissionDialog(Activity activity, TLRPC.User selfUser, Runnable cancelRunnable) { + if (activity == null || Build.VERSION.SDK_INT < 29) { + return null; + } + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + String svg = RLottieDrawable.readRes(null, Theme.getCurrentTheme().isDark() ? R.raw.permission_map_dark : R.raw.permission_map); + String pinSvg = RLottieDrawable.readRes(null, Theme.getCurrentTheme().isDark() ? R.raw.permission_pin_dark : R.raw.permission_pin); + FrameLayout frameLayout = new FrameLayout(activity); + frameLayout.setClipToOutline(true); + frameLayout.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight() + AndroidUtilities.dp(6), AndroidUtilities.dp(6)); + } + }); + + View background = new View(activity); + background.setBackground(SvgHelper.getDrawable(svg)); + frameLayout.addView(background, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 0)); + + View pin = new View(activity); + pin.setBackground(SvgHelper.getDrawable(pinSvg)); + frameLayout.addView(pin, LayoutHelper.createFrame(60, 82, Gravity.CENTER, 0, 0, 0, 0)); + + BackupImageView imageView = new BackupImageView(activity); + imageView.setRoundRadius(AndroidUtilities.dp(26)); + imageView.setImage(ImageLocation.getForUser(selfUser, false), "50_50", (Drawable) null, selfUser); + frameLayout.addView(imageView, LayoutHelper.createFrame(52, 52, Gravity.CENTER, 0, 0, 0, 11)); + + builder.setTopView(frameLayout); + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("PermissionBackgroundLocation", R.string.PermissionBackgroundLocation))); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { + if (activity.checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) { + activity.requestPermissions(new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, 30); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), ((dialog, which) -> cancelRunnable.run())); + return builder; + } + + public static AlertDialog.Builder createContactsPermissionDialog(Activity parentActivity, MessagesStorage.IntCallback callback) { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTopImage(R.drawable.permissions_contacts, Theme.getColor(Theme.key_dialogTopBackground)); builder.setMessage(AndroidUtilities.replaceTags(LocaleController.getString("ContactsPermissionAlert", R.string.ContactsPermissionAlert))); @@ -2618,14 +2666,12 @@ public class AlertsCreator { LocaleController.getString("NotificationsPriorityUrgent", R.string.NotificationsPriorityUrgent) }; } else { - if (dialog_id == 0) { - if (globalType == NotificationsController.TYPE_PRIVATE) { - selected[0] = preferences.getInt("priority_messages", 1); - } else if (globalType == NotificationsController.TYPE_GROUP) { - selected[0] = preferences.getInt("priority_group", 1); - } else if (globalType == NotificationsController.TYPE_CHANNEL) { - selected[0] = preferences.getInt("priority_channel", 1); - } + if (globalType == NotificationsController.TYPE_PRIVATE) { + selected[0] = preferences.getInt("priority_messages", 1); + } else if (globalType == NotificationsController.TYPE_GROUP) { + selected[0] = preferences.getInt("priority_group", 1); + } else if (globalType == NotificationsController.TYPE_CHANNEL) { + selected[0] = preferences.getInt("priority_channel", 1); } if (selected[0] == 4) { selected[0] = 0; @@ -3083,7 +3129,7 @@ public class AlertsCreator { cell.setText(LocaleController.getString("DeleteBanUser", R.string.DeleteBanUser), "", false, false); } else if (a == 1) { cell.setText(LocaleController.getString("DeleteReportSpam", R.string.DeleteReportSpam), "", false, false); - } else if (a == 2) { + } else { cell.setText(LocaleController.formatString("DeleteAllFrom", R.string.DeleteAllFrom, ContactsController.formatName(actionUser.first_name, actionUser.last_name)), "", false, false); } cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(16) : AndroidUtilities.dp(8), 0, LocaleController.isRTL ? AndroidUtilities.dp(8) : AndroidUtilities.dp(16), 0); @@ -3125,7 +3171,12 @@ public class AlertsCreator { } else if (!scheduled && !ChatObject.isChannel(chat) && encryptedChat == null) { if (user != null && user.id != UserConfig.getInstance(currentAccount).getClientUserId() && (!user.bot || user.support) || chat != null) { if (selectedMessage != null) { - boolean hasOutgoing = !selectedMessage.isSendError() && (selectedMessage.messageOwner.action == null || selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionEmpty || selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionPhoneCall) && (selectedMessage.isOut() || canRevokeInbox || ChatObject.hasAdminRights(chat)) && (currentDate - selectedMessage.messageOwner.date) <= revokeTimeLimit; + boolean hasOutgoing = !selectedMessage.isSendError() && ( + selectedMessage.messageOwner.action == null || + selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionEmpty || + selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionPhoneCall || + selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || + selectedMessage.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached) && (selectedMessage.isOut() || canRevokeInbox || ChatObject.hasAdminRights(chat)) && (currentDate - selectedMessage.messageOwner.date) <= revokeTimeLimit; if (hasOutgoing) { myMessagesCount++; } @@ -3134,7 +3185,11 @@ public class AlertsCreator { for (int a = 1; a >= 0; a--) { for (int b = 0; b < selectedMessages[a].size(); b++) { MessageObject msg = selectedMessages[a].valueAt(b); - if (!(msg.messageOwner.action == null || msg.messageOwner.action instanceof TLRPC.TL_messageActionEmpty || msg.messageOwner.action instanceof TLRPC.TL_messageActionPhoneCall)) { + if (!(msg.messageOwner.action == null || + msg.messageOwner.action instanceof TLRPC.TL_messageActionEmpty || + msg.messageOwner.action instanceof TLRPC.TL_messageActionPhoneCall || + msg.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage || + msg.messageOwner.action instanceof TLRPC.TL_messageActionGeoProximityReached)) { continue; } if ((msg.isOut() || canRevokeInbox) || chat != null && ChatObject.canBlockUsers(chat)) { @@ -3207,7 +3262,7 @@ public class AlertsCreator { int channelId = 0; if (!ids.isEmpty()) { MessageObject msg = selectedMessages[a].get(ids.get(0)); - if (channelId == 0 && msg.messageOwner.peer_id.channel_id != 0) { + if (msg.messageOwner.peer_id.channel_id != 0) { channelId = msg.messageOwner.peer_id.channel_id; } } @@ -3241,9 +3296,6 @@ public class AlertsCreator { MessagesController.getInstance(currentAccount).deleteUserChannelHistory(chat, userFinal, 0); } } - if (BulletinFactory.canShowBulletin(fragment)) { - BulletinFactory.createDeleteMessagesBulletin(fragment, count).show(); - } if (onDelete != null) { onDelete.run(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedNumberLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedNumberLayout.java new file mode 100644 index 000000000..d8f621ddd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedNumberLayout.java @@ -0,0 +1,161 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.graphics.Canvas; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.util.Property; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; + +import java.util.ArrayList; +import java.util.Locale; + +public class AnimatedNumberLayout { + + private ArrayList letters = new ArrayList<>(); + private ArrayList oldLetters = new ArrayList<>(); + private final TextPaint textPaint; + private ObjectAnimator animator; + private float progress = 0.0f; + private int currentNumber = 1; + private final View parentView; + + public static final Property PROGRESS = new AnimationProperties.FloatProperty("progress") { + @Override + public void setValue(AnimatedNumberLayout object, float value) { + object.setProgress(value); + } + + @Override + public Float get(AnimatedNumberLayout object) { + return object.progress; + } + }; + + public AnimatedNumberLayout(View parent, TextPaint paint) { + textPaint = paint; + parentView = parent; + } + + private void setProgress(float value) { + if (progress == value) { + return; + } + progress = value; + parentView.invalidate(); + } + + private float getProgress() { + return progress; + } + + public int getWidth() { + float width = 0; + int count = letters.size(); + for (int a = 0; a < count; a++) { + width += letters.get(a).getLineWidth(0); + } + return (int) Math.ceil(width); + } + + public void setNumber(int number, boolean animated) { + if (currentNumber == number && !letters.isEmpty()) { + return; + } + if (animator != null) { + animator.cancel(); + animator = null; + } + oldLetters.clear(); + oldLetters.addAll(letters); + letters.clear(); + String oldText = String.format(Locale.US, "%d", currentNumber); + String text = String.format(Locale.US, "%d", number); + boolean forwardAnimation = number > currentNumber; + currentNumber = number; + progress = 0; + for (int a = 0; a < text.length(); a++) { + String ch = text.substring(a, a + 1); + String oldCh = !oldLetters.isEmpty() && a < oldText.length() ? oldText.substring(a, a + 1) : null; + if (oldCh != null && oldCh.equals(ch)) { + letters.add(oldLetters.get(a)); + oldLetters.set(a, null); + } else { + StaticLayout layout = new StaticLayout(ch, textPaint, (int) Math.ceil(textPaint.measureText(ch)), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + letters.add(layout); + } + } + if (animated && !oldLetters.isEmpty()) { + animator = ObjectAnimator.ofFloat(this, PROGRESS, forwardAnimation ? -1 : 1, 0); + animator.setDuration(150); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animator = null; + oldLetters.clear(); + } + }); + animator.start(); + } + parentView.invalidate(); + } + + public void draw(Canvas canvas) { + if (letters.isEmpty()) { + return; + } + float height = letters.get(0).getHeight(); + int count = Math.max(letters.size(), oldLetters.size()); + canvas.save(); + int currentAlpha = textPaint.getAlpha(); + for (int a = 0; a < count; a++) { + canvas.save(); + StaticLayout old = a < oldLetters.size() ? oldLetters.get(a) : null; + StaticLayout layout = a < letters.size() ? letters.get(a) : null; + if (progress > 0) { + if (old != null) { + textPaint.setAlpha((int) (currentAlpha * progress)); + canvas.save(); + canvas.translate(0, (progress - 1.0f) * height); + old.draw(canvas); + canvas.restore(); + if (layout != null) { + textPaint.setAlpha((int) (currentAlpha * (1.0f - progress))); + canvas.translate(0, progress * height); + } + } else { + textPaint.setAlpha(currentAlpha); + } + } else if (progress < 0) { + if (old != null) { + textPaint.setAlpha((int) (currentAlpha * -progress)); + canvas.save(); + canvas.translate(0, (1.0f + progress) * height); + old.draw(canvas); + canvas.restore(); + } + if (layout != null) { + if (a == count - 1 || old != null) { + textPaint.setAlpha((int) (currentAlpha * (1.0f + progress))); + canvas.translate(0, progress * height); + } else { + textPaint.setAlpha(currentAlpha); + } + } + } else if (layout != null) { + textPaint.setAlpha(currentAlpha); + } + if (layout != null) { + layout.draw(canvas); + } + canvas.restore(); + canvas.translate((layout != null ? layout.getLineWidth(0) : old.getLineWidth(0)), 0); + } + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java index d3df7941b..68f820670 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AudioPlayerAlert.java @@ -13,20 +13,28 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; +import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; + +import androidx.annotation.NonNull; import androidx.core.content.FileProvider; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -53,6 +61,7 @@ import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; @@ -82,6 +91,7 @@ import org.telegram.ui.LaunchActivity; import java.io.File; import java.util.ArrayList; +import java.util.List; public class AudioPlayerAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate, DownloadController.FileDownloadProgressListener { @@ -100,11 +110,11 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. private TextView emptySubtitleTextView; private FrameLayout playerLayout; - private BackupImageView placeholderImageView; - private TextView titleTextView; - private ImageView prevButton; - private ImageView nextButton; - private TextView authorTextView; + private CoverContainer coverContainer; + private ClippingTextViewSwitcher titleTextView; + private RLottieImageView prevButton; + private RLottieImageView nextButton; + private ClippingTextViewSwitcher authorTextView; private ActionBarMenuItem optionsButton; private LineProgressView progressView; private SeekBarView seekBarView; @@ -117,6 +127,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. private ActionBarMenuSubItem shuffleListItem; private ActionBarMenuSubItem reverseOrderItem; private ImageView playButton; + private PlayPauseDrawable playPauseDrawable; private FrameLayout blurredView; private BackupImageView bigAlbumConver; private ActionBarMenuItem searchItem; @@ -134,6 +145,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. private int searchOpenOffset; private ArrayList playlist; + private MessageObject lastMessageObject; private int scrollOffsetY = Integer.MAX_VALUE; private int topBeforeSwitch; @@ -328,6 +340,23 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. canvas.drawRect(backgroundPaddingLeft, 0, getMeasuredWidth() - backgroundPaddingLeft, AndroidUtilities.statusBarHeight, Theme.dialogs_onlineCirclePaint); } } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + Bulletin.addDelegate(this, new Bulletin.Delegate() { + @Override + public int getBottomOffset() { + return playerLayout.getHeight(); + } + }); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Bulletin.removeDelegate(this); + } }; containerView.setWillNotDraw(false); containerView.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); @@ -444,7 +473,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } }; - placeholderImageView = new BackupImageView(context) { + coverContainer = new CoverContainer(context) { private long pressTime; @@ -452,7 +481,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { - if (imageReceiver.hasBitmapImage()) { + if (getImageReceiver().hasBitmapImage()) { showAlbumCover(true, true); pressTime = SystemClock.elapsedRealtime(); } @@ -463,28 +492,41 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } return true; } - }; - placeholderImageView.getImageReceiver().setDelegate((imageReceiver, set, thumb, memCache) -> { - if (blurredView.getTag() != null) { - bigAlbumConver.setImageBitmap(placeholderImageView.imageReceiver.getBitmap()); - } - }); - placeholderImageView.setRoundRadius(AndroidUtilities.dp(4)); - playerLayout.addView(placeholderImageView, LayoutHelper.createFrame(44, 44, Gravity.TOP | Gravity.RIGHT, 0, 20, 20, 0)); - titleTextView = new TextView(context); - titleTextView.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); - titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); - titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - titleTextView.setEllipsize(TextUtils.TruncateAt.END); - titleTextView.setSingleLine(true); + @Override + protected void onImageUpdated(ImageReceiver imageReceiver) { + if (blurredView.getTag() != null) { + bigAlbumConver.setImageBitmap(imageReceiver.getBitmap()); + } + } + }; + playerLayout.addView(coverContainer, LayoutHelper.createFrame(44, 44, Gravity.TOP | Gravity.RIGHT, 0, 20, 20, 0)); + + titleTextView = new ClippingTextViewSwitcher(context) { + @Override + protected TextView createTextView() { + final TextView textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 17); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(true); + return textView; + } + }; playerLayout.addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 20, 20, 72, 0)); - authorTextView = new TextView(context); - authorTextView.setTextColor(Theme.getColor(Theme.key_player_time)); - authorTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); - authorTextView.setEllipsize(TextUtils.TruncateAt.END); - authorTextView.setSingleLine(true); + authorTextView = new ClippingTextViewSwitcher(context) { + @Override + protected TextView createTextView() { + final TextView textView = new TextView(context); + textView.setTextColor(Theme.getColor(Theme.key_player_time)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setSingleLine(true); + return textView; + } + }; playerLayout.addView(authorTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 20, 47, 72, 0)); seekBarView = new SeekBarView(context); @@ -616,20 +658,29 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. updateRepeatButton(); }); - buttons[1] = prevButton = new ImageView(context); + final int iconColor = Theme.getColor(Theme.key_player_button); + + buttons[1] = prevButton = new RLottieImageView(context); prevButton.setScaleType(ImageView.ScaleType.CENTER); - prevButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_button), PorterDuff.Mode.MULTIPLY)); - prevButton.setImageResource(R.drawable.player_new_previous); + prevButton.setAnimation(R.raw.player_prev, 20, 20); + prevButton.setLayerColor("Triangle 3.**", iconColor); + prevButton.setLayerColor("Triangle 4.**", iconColor); + prevButton.setLayerColor("Rectangle 4.**", iconColor); if (Build.VERSION.SDK_INT >= 21) { prevButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 1, AndroidUtilities.dp(22))); } bottomView.addView(prevButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - prevButton.setOnClickListener(v -> MediaController.getInstance().playPreviousMessage()); + prevButton.setOnClickListener(v -> { + MediaController.getInstance().playPreviousMessage(); + prevButton.setProgress(0f); + prevButton.playAnimation(); + }); prevButton.setContentDescription(LocaleController.getString("AccDescrPrevious", R.string.AccDescrPrevious)); buttons[2] = playButton = new ImageView(context); playButton.setScaleType(ImageView.ScaleType.CENTER); - playButton.setImageResource(R.drawable.player_new_play); + playButton.setImageDrawable(playPauseDrawable = new PlayPauseDrawable(28)); + playPauseDrawable.setPause(!MediaController.getInstance().isMessagePaused(), false); playButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_button), PorterDuff.Mode.MULTIPLY)); if (Build.VERSION.SDK_INT >= 21) { playButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 1, AndroidUtilities.dp(24))); @@ -646,18 +697,25 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } }); - buttons[3] = nextButton = new ImageView(context); + buttons[3] = nextButton = new RLottieImageView(context); nextButton.setScaleType(ImageView.ScaleType.CENTER); - nextButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_player_button), PorterDuff.Mode.MULTIPLY)); - nextButton.setImageResource(R.drawable.player_new_next); + nextButton.setAnimation(R.raw.player_prev, 20, 20); + nextButton.setLayerColor("Triangle 3.**", iconColor); + nextButton.setLayerColor("Triangle 4.**", iconColor); + nextButton.setLayerColor("Rectangle 4.**", iconColor); + nextButton.setRotation(180f); if (Build.VERSION.SDK_INT >= 21) { nextButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 1, AndroidUtilities.dp(22))); } bottomView.addView(nextButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); - nextButton.setOnClickListener(v -> MediaController.getInstance().playNextMessage()); + nextButton.setOnClickListener(v -> { + MediaController.getInstance().playNextMessage(); + nextButton.setProgress(0f); + nextButton.playAnimation(); + }); nextButton.setContentDescription(LocaleController.getString("Next", R.string.Next)); - buttons[4] = optionsButton = new ActionBarMenuItem(context, null, 0, Theme.getColor(Theme.key_player_button)); + buttons[4] = optionsButton = new ActionBarMenuItem(context, null, 0, iconColor); optionsButton.setLongClickEnabled(false); optionsButton.setShowSubmenuByMove(false); optionsButton.setIcon(R.drawable.ic_ab_other); @@ -821,6 +879,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. bigAlbumConver = new BackupImageView(context); bigAlbumConver.setAspectFit(true); bigAlbumConver.setRoundRadius(AndroidUtilities.dp(8)); + bigAlbumConver.setScaleX(0.9f); + bigAlbumConver.setScaleY(0.9f); blurredView.addView(bigAlbumConver, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 30, 30, 30, 30)); updateTitle(false); @@ -1065,7 +1125,9 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. if (path == null || path.length() == 0) { path = FileLoader.getPathToMessage(messageObject.messageOwner).toString(); } - MediaController.saveFile(path, parentActivity, 3, fileName, messageObject.getDocument() != null ? messageObject.getDocument().mime_type : ""); + MediaController.saveFile(path, parentActivity, 3, fileName, messageObject.getDocument() != null ? messageObject.getDocument().mime_type : "", () -> { + BulletinFactory.of((FrameLayout) containerView).createDownloadBulletin(BulletinFactory.FileType.AUDIO).show(); + }); } } @@ -1075,7 +1137,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. return; } blurredView.setTag(1); - bigAlbumConver.setImageBitmap(placeholderImageView.imageReceiver.getBitmap()); + bigAlbumConver.setImageBitmap(coverContainer.getImageReceiver().getBitmap()); blurredAnimationInProgress = true; BaseFragment fragment = parentActivity.getActionBarLayout().fragmentsStack.get(parentActivity.getActionBarLayout().fragmentsStack.size() - 1); View fragmentView = fragment.getFragmentView(); @@ -1096,6 +1158,7 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. blurredAnimationInProgress = false; } }).start(); + bigAlbumConver.animate().scaleX(1f).scaleY(1f).setDuration(180).start(); } else { if (blurredView.getVisibility() != View.VISIBLE) { return; @@ -1111,10 +1174,13 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. blurredAnimationInProgress = false; } }).start(); + bigAlbumConver.animate().scaleX(0.9f).scaleY(0.9f).setDuration(180).start(); } else { blurredView.setAlpha(0.0f); blurredView.setVisibility(View.INVISIBLE); bigAlbumConver.setImageBitmap(null); + bigAlbumConver.setScaleX(0.9f); + bigAlbumConver.setScaleY(0.9f); } } } @@ -1358,12 +1424,16 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } private void updateProgress(MessageObject messageObject) { + updateProgress(messageObject, false); + } + + private void updateProgress(MessageObject messageObject, boolean animated) { if (seekBarView != null) { int newTime; if (seekBarView.isDragging()) { newTime = (int) (messageObject.getDuration() * seekBarView.getProgress()); } else { - seekBarView.setProgress(messageObject.audioProgress); + seekBarView.setProgress(messageObject.audioProgress, animated); float bufferedProgress; if (currentAudioFinishedLoading) { @@ -1423,21 +1493,25 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. dismiss(); } else { if (messageObject == null) { + lastMessageObject = null; return; } + final boolean sameMessageObject = messageObject == lastMessageObject; + lastMessageObject = messageObject; if (messageObject.eventId != 0 || messageObject.getId() <= -2000000000) { optionsButton.setVisibility(View.INVISIBLE); } else { optionsButton.setVisibility(View.VISIBLE); } checkIfMusicDownloaded(messageObject); - updateProgress(messageObject); + updateProgress(messageObject, !sameMessageObject); + updateCover(messageObject, !sameMessageObject); if (MediaController.getInstance().isMessagePaused()) { - playButton.setImageResource(R.drawable.player_new_play); + playPauseDrawable.setPause(false); playButton.setContentDescription(LocaleController.getString("AccActionPlay", R.string.AccActionPlay)); } else { - playButton.setImageResource(R.drawable.player_new_pause); + playPauseDrawable.setPause(true); playButton.setContentDescription(LocaleController.getString("AccActionPause", R.string.AccActionPause)); } String title = messageObject.getMusicTitle(); @@ -1445,35 +1519,6 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. titleTextView.setText(title); authorTextView.setText(author); - String loadTitle = author + " " + title; - AudioInfo audioInfo = MediaController.getInstance().getAudioInfo(); - if (audioInfo != null && audioInfo.getCover() != null) { - placeholderImageView.setImageBitmap(audioInfo.getCover()); - currentFile = null; - currentAudioFinishedLoading = true; - } else { - TLRPC.Document document = messageObject.getDocument(); - currentFile = FileLoader.getAttachFileName(document); - currentAudioFinishedLoading = false; - TLRPC.PhotoSize thumb = document != null ? FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 240) : null; - if (!(thumb instanceof TLRPC.TL_photoSize) && !(thumb instanceof TLRPC.TL_photoSizeProgressive)) { - thumb = null; - } - String artworkUrl = messageObject.getArtworkUrl(false); - if (!TextUtils.isEmpty(artworkUrl)) { - if (thumb != null) { - placeholderImageView.setImage(ImageLocation.getForPath(artworkUrl), null, ImageLocation.getForDocument(thumb, document), null, null, 0, 1, messageObject); - } else { - placeholderImageView.setImage(artworkUrl, null, null); - } - } else if (thumb != null) { - placeholderImageView.setImage(null, null, ImageLocation.getForDocument(thumb, document), null, null, 0, 1, messageObject); - } else { - placeholderImageView.setImageDrawable(null); - } - placeholderImageView.invalidate(); - } - int duration = lastDuration = messageObject.getDuration(); if (durationTextView != null) { @@ -1485,6 +1530,91 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. } else { playbackSpeedButton.setVisibility(View.GONE); } + + if (!sameMessageObject) { + preloadNeighboringThumbs(); + } + } + } + + private void updateCover(MessageObject messageObject, boolean animated) { + final BackupImageView imageView = animated ? coverContainer.getNextImageView() : coverContainer.getImageView(); + final AudioInfo audioInfo = MediaController.getInstance().getAudioInfo(); + if (audioInfo != null && audioInfo.getCover() != null) { + imageView.setImageBitmap(audioInfo.getCover()); + currentFile = null; + currentAudioFinishedLoading = true; + } else { + TLRPC.Document document = messageObject.getDocument(); + currentFile = FileLoader.getAttachFileName(document); + currentAudioFinishedLoading = false; + String artworkUrl = messageObject.getArtworkUrl(false); + final ImageLocation thumbImageLocation = getArtworkThumbImageLocation(messageObject); + if (!TextUtils.isEmpty(artworkUrl)) { + imageView.setImage(ImageLocation.getForPath(artworkUrl), null, thumbImageLocation, null, null, 0, 1, messageObject); + } else if (thumbImageLocation != null) { + imageView.setImage(null, null, thumbImageLocation, null, null, 0, 1, messageObject); + } else { + imageView.setImageDrawable(null); + } + imageView.invalidate(); + } + if (animated) { + coverContainer.switchImageViews(); + } + } + + private ImageLocation getArtworkThumbImageLocation(MessageObject messageObject) { + final TLRPC.Document document = messageObject.getDocument(); + TLRPC.PhotoSize thumb = document != null ? FileLoader.getClosestPhotoSizeWithSize(document.thumbs, 240) : null; + if (!(thumb instanceof TLRPC.TL_photoSize) && !(thumb instanceof TLRPC.TL_photoSizeProgressive)) { + thumb = null; + } + if (thumb != null) { + return ImageLocation.getForDocument(thumb, document); + } else { + final String smallArtworkUrl = messageObject.getArtworkUrl(true); + if (smallArtworkUrl != null) { + return ImageLocation.getForPath(smallArtworkUrl); + } + } + return null; + } + + private void preloadNeighboringThumbs() { + final MediaController mediaController = MediaController.getInstance(); + final List playlist = mediaController.getPlaylist(); + if (playlist.size() <= 1) { + return; + } + + final List neighboringItems = new ArrayList<>(); + final int playingIndex = mediaController.getPlayingMessageObjectNum(); + + int nextIndex = playingIndex + 1; + int prevIndex = playingIndex - 1; + if (nextIndex >= playlist.size()) { + nextIndex = 0; + } + if (prevIndex <= -1) { + prevIndex = playlist.size() - 1; + } + + neighboringItems.add(playlist.get(nextIndex)); + if (nextIndex != prevIndex) { + neighboringItems.add(playlist.get(prevIndex)); + } + + for (int i = 0, N = neighboringItems.size(); i < N; i++) { + final MessageObject messageObject = neighboringItems.get(i); + final ImageLocation thumbImageLocation = getArtworkThumbImageLocation(messageObject); + if (thumbImageLocation != null) { + if (thumbImageLocation.path != null) { + ImageLoader.getInstance().preloadArtwork(thumbImageLocation.path); + } else { + FileLoader.getInstance(currentAccount).loadFile(thumbImageLocation, messageObject, null, 0, 1); + } + } } } @@ -1693,8 +1823,8 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. themeDescriptions.add(new ThemeDescription(progressView, 0, null, null, null, null, Theme.key_player_progressBackground)); themeDescriptions.add(new ThemeDescription(progressView, 0, null, null, null, null, Theme.key_player_progress)); themeDescriptions.add(new ThemeDescription(seekBarView, 0, null, null, null, null, Theme.key_player_progressBackground)); - themeDescriptions.add(new ThemeDescription(seekBarView, 0, null, null, null, null, Theme.key_player_progress)); themeDescriptions.add(new ThemeDescription(seekBarView, 0, null, null, null, null, Theme.key_player_progressCachedBackground)); + themeDescriptions.add(new ThemeDescription(seekBarView, ThemeDescription.FLAG_PROGRESSBAR, null, null, null, null, Theme.key_player_progress)); themeDescriptions.add(new ThemeDescription(playbackSpeedButton, ThemeDescription.FLAG_CHECKTAG | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_inappPlayerPlayPause)); themeDescriptions.add(new ThemeDescription(playbackSpeedButton, ThemeDescription.FLAG_CHECKTAG | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_inappPlayerClose)); @@ -1709,13 +1839,17 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. themeDescriptions.add(new ThemeDescription(optionsButton, 0, null, null, null, delegate, Theme.key_actionBarDefaultSubmenuItem)); themeDescriptions.add(new ThemeDescription(optionsButton, 0, null, null, null, delegate, Theme.key_actionBarDefaultSubmenuBackground)); - themeDescriptions.add(new ThemeDescription(prevButton, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(prevButton, 0, null, new RLottieDrawable[]{prevButton.getAnimatedDrawable()}, "Triangle 3", Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(prevButton, 0, null, new RLottieDrawable[]{prevButton.getAnimatedDrawable()}, "Triangle 4", Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(prevButton, 0, null, new RLottieDrawable[]{prevButton.getAnimatedDrawable()}, "Rectangle 4", Theme.key_player_button)); themeDescriptions.add(new ThemeDescription(prevButton, ThemeDescription.FLAG_IMAGECOLOR | ThemeDescription.FLAG_USEBACKGROUNDDRAWABLE, null, null, null, null, Theme.key_listSelector)); themeDescriptions.add(new ThemeDescription(playButton, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_player_button)); themeDescriptions.add(new ThemeDescription(playButton, ThemeDescription.FLAG_IMAGECOLOR | ThemeDescription.FLAG_USEBACKGROUNDDRAWABLE, null, null, null, null, Theme.key_listSelector)); - themeDescriptions.add(new ThemeDescription(nextButton, ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(nextButton, 0, null, new RLottieDrawable[]{nextButton.getAnimatedDrawable()}, "Triangle 3", Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(nextButton, 0, null, new RLottieDrawable[]{nextButton.getAnimatedDrawable()}, "Triangle 4", Theme.key_player_button)); + themeDescriptions.add(new ThemeDescription(nextButton, 0, null, new RLottieDrawable[]{nextButton.getAnimatedDrawable()}, "Rectangle 4", Theme.key_player_button)); themeDescriptions.add(new ThemeDescription(nextButton, ThemeDescription.FLAG_IMAGECOLOR | ThemeDescription.FLAG_USEBACKGROUNDDRAWABLE, null, null, null, null, Theme.key_listSelector)); themeDescriptions.add(new ThemeDescription(playerLayout, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_player_background)); @@ -1736,11 +1870,250 @@ public class AudioPlayerAlert extends BottomSheet implements NotificationCenter. themeDescriptions.add(new ThemeDescription(durationTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_time)); themeDescriptions.add(new ThemeDescription(timeTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_time)); - themeDescriptions.add(new ThemeDescription(titleTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_actionBarTitle)); - themeDescriptions.add(new ThemeDescription(authorTextView, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_time)); + themeDescriptions.add(new ThemeDescription(titleTextView.getTextView(), ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_actionBarTitle)); + themeDescriptions.add(new ThemeDescription(titleTextView.getNextTextView(), ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_actionBarTitle)); + themeDescriptions.add(new ThemeDescription(authorTextView.getTextView(), ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_time)); + themeDescriptions.add(new ThemeDescription(authorTextView.getNextTextView(), ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_time)); themeDescriptions.add(new ThemeDescription(containerView, 0, null, null, null, null, Theme.key_sheet_scrollUp)); return themeDescriptions; } + + private static abstract class CoverContainer extends FrameLayout { + + private final BackupImageView[] imageViews = new BackupImageView[2]; + + private int activeIndex; + private AnimatorSet animatorSet; + + public CoverContainer(@NonNull Context context) { + super(context); + for (int i = 0; i < 2; i++) { + imageViews[i] = new BackupImageView(context); + final int index = i; + imageViews[i].getImageReceiver().setDelegate((imageReceiver, set, thumb, memCache) -> { + if (index == activeIndex) { + onImageUpdated(imageReceiver); + } + }); + imageViews[i].setRoundRadius(AndroidUtilities.dp(4)); + if (i == 1) { + imageViews[i].setVisibility(GONE); + } + addView(imageViews[i], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + } + + public final void switchImageViews() { + if (animatorSet != null) { + animatorSet.cancel(); + } + animatorSet = new AnimatorSet(); + activeIndex = activeIndex == 0 ? 1 : 0; + + final BackupImageView prevImageView = imageViews[activeIndex == 0 ? 1 : 0]; + final BackupImageView currImageView = imageViews[activeIndex]; + + final boolean hasBitmapImage = prevImageView.getImageReceiver().hasBitmapImage(); + + currImageView.setAlpha(hasBitmapImage ? 1f : 0f); + currImageView.setScaleX(0.8f); + currImageView.setScaleY(0.8f); + currImageView.setVisibility(VISIBLE); + + if (hasBitmapImage) { + prevImageView.bringToFront(); + } else { + prevImageView.setVisibility(GONE); + prevImageView.setImageDrawable(null); + } + + final ValueAnimator expandAnimator = ValueAnimator.ofFloat(0.8f, 1f); + expandAnimator.setDuration(125); + expandAnimator.setInterpolator(CubicBezierInterpolator.EASE_OUT); + expandAnimator.addUpdateListener(a -> { + float animatedValue = (float) a.getAnimatedValue(); + currImageView.setScaleX(animatedValue); + currImageView.setScaleY(animatedValue); + if (!hasBitmapImage) { + currImageView.setAlpha(a.getAnimatedFraction()); + } + }); + + if (hasBitmapImage) { + final ValueAnimator collapseAnimator = ValueAnimator.ofFloat(prevImageView.getScaleX(), 0.8f); + collapseAnimator.setDuration(125); + collapseAnimator.setInterpolator(CubicBezierInterpolator.EASE_IN); + collapseAnimator.addUpdateListener(a -> { + float animatedValue = (float) a.getAnimatedValue(); + prevImageView.setScaleX(animatedValue); + prevImageView.setScaleY(animatedValue); + final float fraction = a.getAnimatedFraction(); + if (fraction > 0.25f && !currImageView.getImageReceiver().hasBitmapImage()) { + prevImageView.setAlpha(1f - (fraction - 0.25f) * (1f / 0.75f)); + } + }); + collapseAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + prevImageView.setVisibility(GONE); + prevImageView.setImageDrawable(null); + prevImageView.setAlpha(1f); + } + }); + + animatorSet.playSequentially(collapseAnimator, expandAnimator); + } else { + animatorSet.play(expandAnimator); + } + + animatorSet.start(); + } + + public final BackupImageView getImageView() { + return imageViews[activeIndex]; + } + + public final BackupImageView getNextImageView() { + return imageViews[activeIndex == 0 ? 1 : 0]; + } + + public final ImageReceiver getImageReceiver() { + return getImageView().getImageReceiver(); + } + + protected abstract void onImageUpdated(ImageReceiver imageReceiver); + } + + private abstract static class ClippingTextViewSwitcher extends FrameLayout { + + private final TextView[] textViews = new TextView[2]; + private final float[] clipProgress = new float[]{0f, 0.75f}; + private final int gradientSize = AndroidUtilities.dp(24); + + private final Matrix gradientMatrix; + private final Paint gradientPaint; + private final Paint erasePaint; + + private int activeIndex; + private AnimatorSet animatorSet; + private LinearGradient gradientShader; + + public ClippingTextViewSwitcher(@NonNull Context context) { + super(context); + for (int i = 0; i < 2; i++) { + textViews[i] = createTextView(); + if (i == 1) { + textViews[i].setAlpha(0f); + textViews[i].setVisibility(GONE); + } + addView(textViews[i], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT)); + } + gradientMatrix = new Matrix(); + gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + gradientPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); + erasePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + erasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + gradientShader = new LinearGradient(gradientSize, 0, 0, 0, 0, 0xFF000000, Shader.TileMode.CLAMP); + gradientPaint.setShader(gradientShader); + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + final int index = child == textViews[0] ? 0 : 1; + final boolean result; + if (clipProgress[index] > 0f) { + final int width = child.getWidth(); + final int height = child.getHeight(); + final int saveCount = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG); + result = super.drawChild(canvas, child, drawingTime); + final float gradientStart = width * (1f - clipProgress[index]); + final float gradientEnd = gradientStart + gradientSize; + gradientMatrix.setTranslate(gradientStart, 0); + gradientShader.setLocalMatrix(gradientMatrix); + canvas.drawRect(gradientStart, 0, gradientEnd, height, gradientPaint); + if (width > gradientEnd) { + canvas.drawRect(gradientEnd, 0, width, height, erasePaint); + } + canvas.restoreToCount(saveCount); + } else { + result = super.drawChild(canvas, child, drawingTime); + } + return result; + } + + public void setText(CharSequence text) { + final CharSequence currentText = textViews[activeIndex].getText(); + + if (TextUtils.isEmpty(currentText)) { + textViews[activeIndex].setText(text); + return; + } else if (TextUtils.equals(text, currentText)) { + return; + } + + final int index = activeIndex == 0 ? 1 : 0; + final int prevIndex = activeIndex; + activeIndex = index; + + if (animatorSet != null) { + animatorSet.cancel(); + } + animatorSet = new AnimatorSet(); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + textViews[prevIndex].setVisibility(GONE); + } + }); + + textViews[index].setText(text); + textViews[index].bringToFront(); + textViews[index].setVisibility(VISIBLE); + + final int duration = 300; + + final ValueAnimator collapseAnimator = ValueAnimator.ofFloat(clipProgress[prevIndex], 0.75f); + collapseAnimator.setDuration(duration / 3 * 2); // 0.66 + collapseAnimator.addUpdateListener(a -> { + clipProgress[prevIndex] = (float) a.getAnimatedValue(); + invalidate(); + }); + + final ValueAnimator expandAnimator = ValueAnimator.ofFloat(clipProgress[index], 0f); + expandAnimator.setStartDelay(duration / 3); // 0.33 + expandAnimator.setDuration(duration / 3 * 2); // 0.66 + expandAnimator.addUpdateListener(a -> { + clipProgress[index] = (float) a.getAnimatedValue(); + invalidate(); + }); + + final ObjectAnimator fadeOutAnimator = ObjectAnimator.ofFloat(textViews[prevIndex], View.ALPHA, 0f); + fadeOutAnimator.setStartDelay(duration / 4); // 0.25 + fadeOutAnimator.setDuration(duration / 2); // 0.5 + + final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(textViews[index], View.ALPHA, 1f); + fadeInAnimator.setStartDelay(duration / 4); // 0.25 + fadeInAnimator.setDuration(duration / 2); // 0.5 + + animatorSet.playTogether(collapseAnimator, expandAnimator, fadeOutAnimator, fadeInAnimator); + animatorSet.start(); + } + + public TextView getTextView() { + return textViews[activeIndex]; + } + + public TextView getNextTextView() { + return textViews[activeIndex == 0 ? 1 : 0]; + } + + protected abstract TextView createTextView(); + } } \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java index 85ca7322a..2d1bb7bed 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Bulletin.java @@ -13,6 +13,7 @@ import android.graphics.Typeface; import android.graphics.drawable.InsetDrawable; import android.os.Build; import android.util.TypedValue; +import android.view.GestureDetector; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -30,8 +31,10 @@ import androidx.core.util.Preconditions; import androidx.core.view.ViewCompat; import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.BaseFragment; @@ -81,25 +84,33 @@ public final class Bulletin { private static Bulletin visibleBulletin; private final Layout layout; - private final FrameLayout parentLayout; + private final ParentLayout parentLayout; private final FrameLayout containerLayout; + private final Runnable hideRunnable = this::hide; private final int duration; private boolean showing; - private Runnable exitRunnable; + private boolean canHide; private int currentBottomOffset; private Delegate currentDelegate; private Layout.Transition layoutTransition; private Bulletin(@NonNull FrameLayout containerLayout, @NonNull Layout layout, int duration) { this.layout = layout; - this.parentLayout = new FrameLayout(layout.getContext()); - this.parentLayout.addView(layout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + this.parentLayout = new ParentLayout(layout) { + @Override + protected void onPressedStateChanged(boolean pressed) { + setCanHide(!pressed); + if (containerLayout.getParent() != null) { + containerLayout.getParent().requestDisallowInterceptTouchEvent(pressed); + } + } + }; this.containerLayout = containerLayout; this.duration = duration; } - public void show() { + public Bulletin show() { if (!showing) { showing = true; @@ -128,7 +139,7 @@ public final class Bulletin { ensureLayoutTransitionCreated(); layoutTransition.animateEnter(layout, layout::onEnterTransitionStart, () -> { layout.onEnterTransitionEnd(); - layout.postDelayed(exitRunnable = Bulletin.this::hide, duration); + setCanHide(true); }, offset -> { if (currentDelegate != null) { currentDelegate.onOffsetChange(layout.getHeight() - offset); @@ -141,7 +152,7 @@ public final class Bulletin { layout.setTranslationY(-currentBottomOffset); layout.onEnterTransitionStart(); layout.onEnterTransitionEnd(); - layout.postDelayed(exitRunnable = Bulletin.this::hide, duration); + setCanHide(true); } } } @@ -160,6 +171,18 @@ public final class Bulletin { containerLayout.addView(parentLayout); } + return this; + } + + private void setCanHide(boolean canHide) { + if (this.canHide != canHide) { + this.canHide = canHide; + if (canHide) { + layout.postDelayed(hideRunnable, duration); + } else { + layout.removeCallbacks(hideRunnable); + } + } } private void ensureLayoutTransitionCreated() { @@ -172,8 +195,8 @@ public final class Bulletin { hide(isTransitionsEnabled()); } - private void hide(boolean animated) { - if (showing) { + public void hide(boolean animated) { + if (showing && canHide) { showing = false; if (visibleBulletin == this) { @@ -184,10 +207,7 @@ public final class Bulletin { currentBottomOffset = 0; if (ViewCompat.isLaidOut(layout)) { - if (exitRunnable != null) { - layout.removeCallbacks(exitRunnable); - exitRunnable = null; - } + layout.removeCallbacks(hideRunnable); if (animated) { ensureLayoutTransitionCreated(); layoutTransition.animateExit(layout, layout::onExitTransitionStart, () -> { @@ -232,6 +252,85 @@ public final class Bulletin { return MessagesController.getGlobalMainSettings().getBoolean("view_animations", true) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; } + private static abstract class ParentLayout extends FrameLayout { + + private final Layout layout; + private final Rect rect = new Rect(); + private final GestureDetector gestureDetector; + + private boolean pressed; + private float translationX; + private SpringAnimation springAnimation; + + public ParentLayout(Layout layout) { + super(layout.getContext()); + this.layout = layout; + gestureDetector = new GestureDetector(layout.getContext(), new GestureDetector.SimpleOnGestureListener() { + + @Override + public boolean onDown(MotionEvent e) { + return springAnimation == null; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + layout.setTranslationX(translationX -= distanceX); + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (Math.abs(velocityX) > 2000f) { + springAnimation = new SpringAnimation(layout, DynamicAnimation.TRANSLATION_X, Math.signum(velocityX) * layout.getWidth() * 2f); + springAnimation.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY); + springAnimation.getSpring().setStiffness(100f); + springAnimation.setStartVelocity(velocityX); + springAnimation.start(); + return true; + } + return false; + } + }); + gestureDetector.setIsLongpressEnabled(false); + addView(layout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (pressed || inLayoutHitRect(event.getX(), event.getY())) { + gestureDetector.onTouchEvent(event); + final int actionMasked = event.getActionMasked(); + if (actionMasked == MotionEvent.ACTION_DOWN) { + if (!pressed && springAnimation == null) { + layout.animate().cancel(); + translationX = layout.getTranslationX(); + onPressedStateChanged(pressed = true); + } + } else if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL) { + if (pressed) { + if (springAnimation == null) { + if (Math.abs(translationX) > layout.getWidth() / 2) { + layout.animate().translationX(Math.signum(translationX) * layout.getWidth()).setDuration(200).setInterpolator(AndroidUtilities.accelerateInterpolator).start(); + } else { + layout.animate().translationX(0).setDuration(200).start(); + } + } + onPressedStateChanged(pressed = false); + } + } + return true; + } + return false; + } + + private boolean inLayoutHitRect(float x, float y) { + layout.getHitRect(rect); + return rect.contains((int) x, (int) y); + } + + protected abstract void onPressedStateChanged(boolean pressed); + } + //region Offset Providers public static void addDelegate(@NonNull BaseFragment fragment, @NonNull Delegate delegate) { final FrameLayout containerLayout = fragment.getLayoutContainer(); @@ -297,12 +396,6 @@ public final class Bulletin { setLayoutParams(LayoutHelper.createFrame(matchParentWidth ? LayoutHelper.MATCH_PARENT : LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL)); } - @Override - public boolean onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); - return true; - } - public Bulletin getBulletin() { return bulletin; } @@ -481,22 +574,14 @@ public final class Bulletin { springAnimation.getSpring().setDampingRatio(DAMPING_RATIO); springAnimation.getSpring().setStiffness(STIFFNESS); if (endAction != null) { - springAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() { - @Override - public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { - if (!canceled) { - endAction.run(); - } + springAnimation.addEndListener((animation, canceled, value, velocity) -> { + if (!canceled) { + endAction.run(); } }); } if (onUpdate != null) { - springAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { - @Override - public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) { - onUpdate.accept(value); - } - }); + springAnimation.addUpdateListener((animation, value, velocity) -> onUpdate.accept(value)); } springAnimation.start(); if (startAction != null) { @@ -510,22 +595,14 @@ public final class Bulletin { springAnimation.getSpring().setDampingRatio(DAMPING_RATIO); springAnimation.getSpring().setStiffness(STIFFNESS); if (endAction != null) { - springAnimation.addEndListener(new DynamicAnimation.OnAnimationEndListener() { - @Override - public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { - if (!canceled) { - endAction.run(); - } + springAnimation.addEndListener((animation, canceled, value, velocity) -> { + if (!canceled) { + endAction.run(); } }); } if (onUpdate != null) { - springAnimation.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { - @Override - public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) { - onUpdate.accept(value); - } - }); + springAnimation.addUpdateListener((animation, value, velocity) -> onUpdate.accept(value)); } springAnimation.start(); if (startAction != null) { @@ -644,6 +721,60 @@ public final class Bulletin { subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); linearLayout.addView(subtitleTextView); } + + } + + public static class TwoLineLottieLayout extends ButtonLayout { + + public final RLottieImageView imageView; + public final TextView titleTextView; + public final TextView subtitleTextView; + + private final int textColor; + + public TwoLineLottieLayout(@NonNull Context context) { + this(context, Theme.getColor(Theme.key_undo_background), Theme.getColor(Theme.key_undo_infoColor)); + } + + public TwoLineLottieLayout(@NonNull Context context, @ColorInt int backgroundColor, @ColorInt int textColor) { + super(context, backgroundColor); + this.textColor = textColor; + + imageView = new RLottieImageView(context); + addView(imageView, LayoutHelper.createFrameRelatively(28, 28, Gravity.START | Gravity.CENTER_VERTICAL, 14, 10, 14, 10)); + + final int undoInfoColor = Theme.getColor(Theme.key_undo_infoColor); + + final LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.VERTICAL); + addView(linearLayout, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.START | Gravity.CENTER_VERTICAL, 54, 8, 12, 8)); + + titleTextView = new TextView(context); + titleTextView.setSingleLine(); + titleTextView.setTextColor(undoInfoColor); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + linearLayout.addView(titleTextView); + + subtitleTextView = new TextView(context); + subtitleTextView.setTextColor(undoInfoColor); + subtitleTextView.setTypeface(Typeface.SANS_SERIF); + subtitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + linearLayout.addView(subtitleTextView); + } + + @Override + protected void onShow() { + super.onShow(); + imageView.playAnimation(); + } + + public void setAnimation(int resId, String... layers) { + imageView.setAnimation(resId, 28, 28); + for (int i = 0; i < layers.length; i++) { + imageView.setLayerColor(layers[i] + ".**", textColor); + } + } } public static class LottieLayout extends ButtonLayout { @@ -736,18 +867,31 @@ public final class Bulletin { private Bulletin bulletin; private boolean isUndone; - public UndoButton(@NonNull Context context) { + public UndoButton(@NonNull Context context, boolean text) { super(context); final int undoCancelColor = Theme.getColor(Theme.key_undo_cancelColor); - final ImageView undoImageView = new ImageView(getContext()); - undoImageView.setOnClickListener(v -> undo()); - undoImageView.setImageResource(R.drawable.chats_undo); - undoImageView.setColorFilter(new PorterDuffColorFilter(undoCancelColor, PorterDuff.Mode.SRC_IN)); - undoImageView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000)); - ViewHelper.setPaddingRelative(undoImageView, 0, 12, 0, 12); - addView(undoImageView, LayoutHelper.createFrameRelatively(56, 48, Gravity.CENTER_VERTICAL)); + if (text) { + TextView undoTextView = new TextView(context); + undoTextView.setOnClickListener(v -> undo()); + undoTextView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000, 7)); + undoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + undoTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + undoTextView.setTextColor(undoCancelColor); + undoTextView.setText(LocaleController.getString("Undo", R.string.Undo)); + undoTextView.setGravity(Gravity.CENTER_VERTICAL); + ViewHelper.setPaddingRelative(undoTextView, 16, 0, 16, 0); + addView(undoTextView, LayoutHelper.createFrameRelatively(LayoutHelper.WRAP_CONTENT, 48, Gravity.CENTER_VERTICAL, 0, 0, 0, 0)); + } else { + final ImageView undoImageView = new ImageView(getContext()); + undoImageView.setOnClickListener(v -> undo()); + undoImageView.setImageResource(R.drawable.chats_undo); + undoImageView.setColorFilter(new PorterDuffColorFilter(undoCancelColor, PorterDuff.Mode.SRC_IN)); + undoImageView.setBackground(Theme.createSelectorDrawable((undoCancelColor & 0x00ffffff) | 0x19000000)); + ViewHelper.setPaddingRelative(undoImageView, 0, 12, 0, 12); + addView(undoImageView, LayoutHelper.createFrameRelatively(56, 48, Gravity.CENTER_VERTICAL)); + } } public void undo() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java index 896683316..05d34a448 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BulletinFactory.java @@ -1,9 +1,11 @@ package org.telegram.ui.Components; +import android.content.Context; import android.widget.FrameLayout; import androidx.core.util.Preconditions; +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; @@ -11,13 +13,112 @@ import org.telegram.ui.ActionBar.BaseFragment; public final class BulletinFactory { - private BulletinFactory() { + public static BulletinFactory of(BaseFragment fragment) { + Preconditions.checkNotNull(fragment); + return new BulletinFactory(fragment); + } + + public static BulletinFactory of(FrameLayout containerLayout) { + Preconditions.checkNotNull(containerLayout); + return new BulletinFactory(containerLayout); } public static boolean canShowBulletin(BaseFragment fragment) { - return fragment != null && fragment.getParentActivity() != null; + return fragment != null && fragment.getParentActivity() != null && fragment.getLayoutContainer() != null; } + public enum FileType { + PHOTO("PhotoSavedHint", R.string.PhotoSavedHint), + PHOTO_TO_DOWNLOADS("PhotoSavedToDownloadsHint", R.string.PhotoSavedToDownloadsHint), + PHOTOS("PhotosSavedHint"), + + VIDEO("VideoSavedHint", R.string.VideoSavedHint), + VIDEO_TO_DOWNLOADS("VideoSavedToDownloadsHint", R.string.VideoSavedToDownloadsHint), + VIDEOS("VideosSavedHint"), + + AUDIO("AudioSavedHint", R.string.AudioSavedHint), + AUDIOS("AudiosSavedHint"), + GIF("GifSavedToDownloadsHint", R.string.GifSavedToDownloadsHint), + MEDIA("MediaSavedHint"), + + UNKNOWN("FileSavedHint", R.string.FileSavedHint), + UNKNOWNS("FilesSavedHint"); + + private final String localeKey; + private final int localeRes; + private final boolean plural; + + FileType(String localeKey, int localeRes) { + this.localeKey = localeKey; + this.localeRes = localeRes; + this.plural = false; + } + + FileType(String localeKey) { + this.localeKey = localeKey; + this.localeRes = 0; + this.plural = true; + } + + private String getText() { + return getText(1); + } + + private String getText(int amount) { + if (plural) { + return LocaleController.formatPluralString(localeKey, amount); + } else { + return LocaleController.getString(localeKey, localeRes); + } + } + } + + private final BaseFragment fragment; + private final FrameLayout containerLayout; + + private BulletinFactory(BaseFragment fragment) { + this.fragment = fragment; + this.containerLayout = null; + } + + private BulletinFactory(FrameLayout containerLayout) { + this.containerLayout = containerLayout; + this.fragment = null; + } + + public Bulletin createDownloadBulletin(FileType fileType) { + return createDownloadBulletin(fileType, 1); + } + + public Bulletin createDownloadBulletin(FileType fileType, int filesAmount) { + return createDownloadBulletin(fileType, filesAmount, 0, 0); + } + + public Bulletin createDownloadBulletin(FileType fileType, int filesAmount, int backgroundColor, int textColor) { + final Bulletin.LottieLayout layout; + if (backgroundColor != 0 && textColor != 0) { + layout = new Bulletin.LottieLayout(getContext(), backgroundColor, textColor); + } else { + layout = new Bulletin.LottieLayout(getContext()); + } + layout.setAnimation(R.raw.ic_download, "Box", "Arrow", "Mask", "Arrow 2", "Splash"); + layout.textView.setText(fileType.getText(filesAmount)); + return create(layout, Bulletin.DURATION_SHORT); + } + + private Bulletin create(Bulletin.Layout layout, int duration) { + if (fragment != null) { + return Bulletin.make(fragment, layout, duration); + } else { + return Bulletin.make(containerLayout, layout, duration); + } + } + + private Context getContext() { + return fragment != null ? fragment.getParentActivity() : containerLayout.getContext(); + } + + //region Static Factory public static Bulletin createMuteBulletin(BaseFragment fragment, int setting) { Preconditions.checkArgument(canShowBulletin(fragment)); final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity()); @@ -72,16 +173,58 @@ public final class BulletinFactory { return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); } - public static Bulletin createSaveToGalleryBulletin(FrameLayout containerLayout, boolean video, int backgroundColor, int textColor) { - Preconditions.checkNotNull(containerLayout); - final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(containerLayout.getContext(), backgroundColor, textColor); - layout.imageView.setAnimation(R.raw.ic_download, 28, 28); - layout.setAnimation(R.raw.ic_download, "Box", "Arrow", "Mask", "Arrow 2", "Splash"); - if (video) { - layout.textView.setText(LocaleController.getString("VideoSavedHint", R.string.VideoSavedHint)); + public static Bulletin createUnpinAllMessagesBulletin(BaseFragment fragment, int count, boolean hide, Runnable undoAction, Runnable delayedAction) { + Preconditions.checkArgument(canShowBulletin(fragment)); + Bulletin.ButtonLayout buttonLayout; + if (hide) { + final Bulletin.TwoLineLottieLayout layout = new Bulletin.TwoLineLottieLayout(fragment.getParentActivity()); + layout.setAnimation(R.raw.ic_unpin, "Pin", "Line"); + layout.titleTextView.setText(LocaleController.getString("PinnedMessagesHidden", R.string.PinnedMessagesHidden)); + layout.subtitleTextView.setText(LocaleController.getString("PinnedMessagesHiddenInfo", R.string.PinnedMessagesHiddenInfo)); + buttonLayout = layout; } else { - layout.textView.setText(LocaleController.getString("PhotoSavedHint", R.string.PhotoSavedHint)); + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity()); + layout.setAnimation(R.raw.ic_unpin, "Pin", "Line"); + layout.textView.setText(LocaleController.formatPluralString("MessagesUnpinned", count)); + buttonLayout = layout; } - return Bulletin.make(containerLayout, layout, Bulletin.DURATION_SHORT); + buttonLayout.setButton(new Bulletin.UndoButton(fragment.getParentActivity(), true).setUndoAction(undoAction).setDelayedAction(delayedAction)); + return Bulletin.make(fragment, buttonLayout, 5000); } + + public static Bulletin createSaveToGalleryBulletin(BaseFragment fragment, boolean video) { + return of(fragment).createDownloadBulletin(video ? FileType.VIDEO : FileType.PHOTO); + } + + public static Bulletin createSaveToGalleryBulletin(FrameLayout containerLayout, boolean video, int backgroundColor, int textColor) { + return of(containerLayout).createDownloadBulletin(video ? FileType.VIDEO : FileType.PHOTO, 1, backgroundColor, textColor); + } + + public static Bulletin createPromoteToAdminBulletin(BaseFragment fragment, String userFirstName) { + Preconditions.checkArgument(canShowBulletin(fragment)); + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity()); + layout.setAnimation(R.raw.ic_admin, "Shield"); + layout.textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("UserSetAsAdminHint", R.string.UserSetAsAdminHint, userFirstName))); + return Bulletin.make(fragment, layout, Bulletin.DURATION_SHORT); + } + + public static Bulletin createPinMessageBulletin(BaseFragment fragment) { + return createPinMessageBulletin(fragment, true, null, null); + } + + public static Bulletin createUnpinMessageBulletin(BaseFragment fragment, Runnable undoAction, Runnable delayedAction) { + return createPinMessageBulletin(fragment, false, undoAction, delayedAction); + } + + private static Bulletin createPinMessageBulletin(BaseFragment fragment, boolean pinned, Runnable undoAction, Runnable delayedAction) { + Preconditions.checkArgument(canShowBulletin(fragment)); + final Bulletin.LottieLayout layout = new Bulletin.LottieLayout(fragment.getParentActivity()); + layout.setAnimation(pinned ? R.raw.ic_pin : R.raw.ic_unpin, "Pin", "Line"); + layout.textView.setText(LocaleController.getString(pinned ? "MessagePinnedHint" : "MessageUnpinnedHint", pinned ? R.string.MessagePinnedHint : R.string.MessageUnpinnedHint)); + if (!pinned) { + layout.setButton(new Bulletin.UndoButton(fragment.getParentActivity(), true).setUndoAction(undoAction).setDelayedAction(delayedAction)); + } + return Bulletin.make(fragment, layout, pinned ? Bulletin.DURATION_SHORT : 5000); + } + //endregion } 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 31de9a50a..04bf8ba71 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -48,6 +48,7 @@ import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.TextUtils; import android.text.TextWatcher; import android.text.style.ImageSpan; import android.util.Property; @@ -151,6 +152,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe private boolean clearBotButtonsOnKeyboardOpen; private boolean expandStickersWithKeyboard; + public int getHeightWithTopView() { + int h = getMeasuredHeight(); + if (topView != null && topView.getVisibility() == View.VISIBLE) { + h -= (1f - topViewEnterProgress) * topView.getLayoutParams().height; + } + return h; + } + public interface ChatActivityEnterViewDelegate { void onMessageSend(CharSequence message, boolean notify, int scheduleDate); @@ -213,6 +222,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe default void prepareMessageSending() { } + + default void onTrendingStickersShowed(boolean show) { + + } } private final static int RECORD_STATE_ENTER = 0; @@ -232,6 +245,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe private AdjustPanLayoutHelper adjustPanLayoutHelper; private Runnable showTopViewRunnable; private Runnable setTextFieldRunnable; + public boolean preventInput; private class SeekBarWaveformView extends View { @@ -477,16 +491,11 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe boolean prevOpen2 = emojiTabOpen; emojiTabOpen = curPage == 0; if (stickersExpanded) { - if (!stickersTabOpen && searchingType == 0) { - if (searchingType != 0) { - searchingType = 0; - emojiView.closeSearch(true); - emojiView.hideSearchKeyboard(); - } - setStickersExpanded(false, true, false); - } else if (searchingType != 0) { + if (searchingType != 0) { searchingType = curPage == 0 ? 2 : 1; checkStickresExpandHeight(); + } else if (!stickersTabOpen) { + setStickersExpanded(false, true, false); } } if (prevOpen != stickersTabOpen || prevOpen2 != emojiTabOpen) { @@ -2037,6 +2046,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe @Override public boolean onTouchEvent(MotionEvent event) { + if (stickersDragging || stickersExpansionAnim != null) { + return false; + } if (isPopupShowing() && event.getAction() == MotionEvent.ACTION_DOWN) { if (searchingType != 0) { searchingType = 0; @@ -2063,6 +2075,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return false; } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (preventInput) { + return false; + } + return super.dispatchKeyEvent(event); + } + @Override protected void onSelectionChanged(int selStart, int selEnd) { super.onSelectionChanged(selStart, selEnd); @@ -2193,9 +2213,6 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if ((ctrlPressed || sendByEnter) && keyEvent.getAction() == KeyEvent.ACTION_DOWN && editingMessageObject == null) { sendMessage(); return true; - } else if (i == KeyEvent.KEYCODE_CTRL_LEFT || i == KeyEvent.KEYCODE_CTRL_RIGHT) { - ctrlPressed = keyEvent.getAction() == KeyEvent.ACTION_DOWN; - return true; } } return false; @@ -2230,7 +2247,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe CharSequence message = AndroidUtilities.getTrimmedString(charSequence.toString()); if (delegate != null) { if (!ignoreTextChange) { - if (count > 2 || charSequence == null || charSequence.length() == 0) { + if (count > 2 || TextUtils.isEmpty(charSequence)) { messageWebPageSearch = true; } delegate.onTextChanged(charSequence, before > count + 1 || (count - before) > 2); @@ -2240,14 +2257,6 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe processChange = true; } if (editingMessageObject == null && !canWriteToChannel && message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { - int currentTime = ConnectionsManager.getInstance(currentAccount).getCurrentTime(); - TLRPC.User currentUser = null; - if ((int) dialog_id > 0) { - currentUser = accountInstance.getMessagesController().getUser((int) dialog_id); - } - if (currentUser != null && (currentUser.id == UserConfig.getInstance(currentAccount).getClientUserId() || currentUser.status != null && currentUser.status.expires < currentTime && !accountInstance.getMessagesController().onlinePrivacy.containsKey(currentUser.id))) { - return; - } lastTypingTimeSend = System.currentTimeMillis(); if (delegate != null) { delegate.needSendTyping(); @@ -2328,7 +2337,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe SharedPreferences preferences1 = MessagesController.getMainSettings(currentAccount); preferences1.edit().remove("hidekeyboard_" + dialog_id).apply(); } else { - if (currentPopupContentType == 1 && botButtonsMessageObject != null) { + if (botButtonsMessageObject != null) { SharedPreferences preferences1 = MessagesController.getMainSettings(currentAccount); preferences1.edit().putInt("hidekeyboard_" + dialog_id, botButtonsMessageObject.getId()).commit(); } @@ -2929,7 +2938,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } sendButtonContainer.addView(expandStickersButton, LayoutHelper.createFrame(48, 48)); expandStickersButton.setOnClickListener(v -> { - if (expandStickersButton.getVisibility() != VISIBLE || expandStickersButton.getAlpha() != 1.0f) { + if (expandStickersButton.getVisibility() != VISIBLE || expandStickersButton.getAlpha() != 1.0f || waitingForKeyboardOpen || (keyboardVisible && messageEditText.isFocused())) { return; } if (stickersExpanded) { @@ -4039,12 +4048,12 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } replyingMessageObject = messageObject; setButtons(replyingMessageObject, true); - } else if (messageObject == null && replyingMessageObject == botButtonsMessageObject) { + } else if (replyingMessageObject == botButtonsMessageObject) { replyingMessageObject = null; setButtons(botMessageObject, false); botMessageObject = null; } else { - replyingMessageObject = messageObject; + replyingMessageObject = null; } MediaController.getInstance().setReplyingMessage(messageObject, getThreadMessage()); } @@ -4143,27 +4152,32 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } exitAnimation.setDuration(200); - attachButton.setAlpha(0f); + AnimatorSet attachIconAnimator; + if (attachButton != null) { + attachButton.setAlpha(0f); + attachButton.setScaleX(0); + attachButton.setScaleY(0); + + attachIconAnimator = new AnimatorSet(); + attachIconAnimator.playTogether( + ObjectAnimator.ofFloat(attachButton, View.ALPHA, 1.0f), + ObjectAnimator.ofFloat(attachButton, View.SCALE_X, 1.0f), + ObjectAnimator.ofFloat(attachButton, View.SCALE_Y, 1.0f) + ); + attachIconAnimator.setDuration(150); + } else { + attachIconAnimator = null; + } + emojiButton[0].setAlpha(0f); emojiButton[1].setAlpha(0f); - attachButton.setScaleX(0); emojiButton[0].setScaleX(0); emojiButton[1].setScaleX(0); - attachButton.setScaleY(0); emojiButton[0].setScaleY(0); emojiButton[1].setScaleY(0); - AnimatorSet attachIconAnimator = new AnimatorSet(); - attachIconAnimator.playTogether( - ObjectAnimator.ofFloat(attachButton, View.ALPHA, 1.0f), - ObjectAnimator.ofFloat(attachButton, View.SCALE_X, 1.0f), - ObjectAnimator.ofFloat(attachButton, View.SCALE_Y, 1.0f) - ); - - attachIconAnimator.setDuration(150); - AnimatorSet iconsEndAnimator = new AnimatorSet(); iconsEndAnimator.playTogether( @@ -4184,12 +4198,18 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe iconsEndAnimator.setStartDelay(600); recordPannelAnimation = new AnimatorSet(); - recordPannelAnimation.playTogether( - exitAnimation, - attachIconAnimator, - iconsEndAnimator - - ); + if (attachIconAnimator != null) { + recordPannelAnimation.playTogether( + exitAnimation, + attachIconAnimator, + iconsEndAnimator + ); + } else { + recordPannelAnimation.playTogether( + exitAnimation, + iconsEndAnimator + ); + } recordPannelAnimation.addListener(new AnimatorListenerAdapter() { @Override @@ -4707,7 +4727,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe runningAnimation2 = null; } - if (attachLayout != null || recordInterfaceState == 0) { + if (attachLayout != null && recordInterfaceState == 0) { attachLayout.setVisibility(VISIBLE); runningAnimation2 = new AnimatorSet(); ArrayList animators = new ArrayList<>(); @@ -6046,12 +6066,8 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (AndroidUtilities.isTablet()) { if (parentActivity instanceof LaunchActivity) { LaunchActivity launchActivity = (LaunchActivity) parentActivity; - if (launchActivity != null) { - View layout = launchActivity.getLayersActionBarLayout(); - allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; - } else { - allowFocus = true; - } + View layout = launchActivity.getLayersActionBarLayout(); + allowFocus = layout == null || layout.getVisibility() != View.VISIBLE; } else { allowFocus = true; } @@ -6130,11 +6146,11 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe scheduledButton.setAlpha(visible ? 1.0f : 0.0f); scheduledButton.setScaleX(visible ? 1.0f : 0.1f); scheduledButton.setScaleY(visible ? 1.0f : 0.1f); + if (notifyButton != null) { + notifyButton.setVisibility(notifyVisible && scheduledButton.getVisibility() != VISIBLE ? VISIBLE : GONE); + } } - if (notifyButton != null) { - notifyButton.setVisibility(notifyVisible && scheduledButton.getVisibility() != VISIBLE ? VISIBLE : GONE); - } - } else { + } else if (scheduledButton != null) { if (visible) { scheduledButton.setVisibility(VISIBLE); } @@ -6347,7 +6363,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe Bundle args1 = new Bundle(); if (lower_part > 0) { args1.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { args1.putInt("chat_id", -lower_part); } if (!accountInstance.getMessagesController().checkCanOpenChat(args1, fragment1)) { @@ -6622,8 +6638,14 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe if (trendingStickersAlert == this) { trendingStickersAlert = null; } + if (delegate != null) { + delegate.onTrendingStickersShowed(false); + } } }; + if (delegate != null) { + delegate.onTrendingStickersShowed(true); + } trendingStickersAlert.show(); } } @@ -6696,7 +6718,7 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe } private boolean allowDragging() { - return stickersTabOpen && !(!stickersExpanded && messageEditText.length() > 0) && emojiView.areThereAnyStickers(); + return stickersTabOpen && !(!stickersExpanded && messageEditText.length() > 0) && emojiView.areThereAnyStickers() && !waitingForKeyboardOpen; } }); sizeNotifierLayout.addView(emojiView, sizeNotifierLayout.getChildCount() - 1); @@ -7094,6 +7116,9 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe showKeyboardOnResume = true; } else if (!AndroidUtilities.usingHardwareInput && !keyboardVisible && !AndroidUtilities.isInMultiwindow && (parentFragment == null || !parentFragment.isInBubbleMode())) { waitingForKeyboardOpen = true; + if (emojiView != null) { + emojiView.onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL, 0, 0, 0)); + } AndroidUtilities.cancelRunOnUIThread(openKeyboardRunnable); AndroidUtilities.runOnUIThread(openKeyboardRunnable, 100); } @@ -7692,6 +7717,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe this.adjustPanLayoutHelper = adjustPanLayoutHelper; } + public AdjustPanLayoutHelper getAdjustPanLayoutHelper() { + return adjustPanLayoutHelper; + } + public boolean pannelAniamationInProgress() { return panelAnimation != null; } @@ -7707,6 +7736,10 @@ public class ChatActivityEnterView extends FrameLayout implements NotificationCe return animatedTop; } + public void checkAnimation() { + + } + private class ScrimDrawable extends Drawable { private Paint paint; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java index ba2815cf0..461818cb2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java @@ -332,6 +332,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N protected int avatarPicker; protected boolean avatarSearch; + protected boolean typeButtonsAvailable; private int selectedId; @@ -348,6 +349,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N private float baseSelectedTextViewTranslationY; private boolean menuShowed; protected SizeNotifierFrameLayout sizeNotifierFrameLayout; + private boolean openTransitionFinished; private Object viewChangeAnimator; @@ -623,7 +625,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override protected boolean heightAnimationEnabled() { - if (isDismissed()) { + if (isDismissed() || !openTransitionFinished) { return false; } return !commentTextView.isPopupVisible(); @@ -1214,13 +1216,13 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); return; } - openAudioLayout(); + openAudioLayout(true); } else if (num == 4) { if (Build.VERSION.SDK_INT >= 23 && baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { baseFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); return; } - openDocumentsLayout(); + openDocumentsLayout(true); } else if (num == 5) { if (Build.VERSION.SDK_INT >= 23) { if (baseFragment.getParentActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { @@ -1696,6 +1698,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N ChatActivity chatActivity = (ChatActivity) baseFragment; calcMandatoryInsets = chatActivity.isKeyboardVisible(); } + openTransitionFinished = false; } public void setEditingMessageObject(MessageObject messageObject) { @@ -1836,6 +1839,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == 5 && grantResults != null && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { openContactsLayout(); + } else if (requestCode == 30 && locationLayout != null && currentAttachLayout == locationLayout && isShowing()) { + locationLayout.openShareLiveLocation(); } } @@ -1847,7 +1852,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N showLayout(contactsLayout); } - private void openAudioLayout() { + private void openAudioLayout(boolean show) { if (audioLayout == null) { layouts[3] = audioLayout = new ChatAttachAlertAudioLayout(this, getContext()); audioLayout.setDelegate((audios, caption, notify, scheduleDate) -> ((ChatActivity) baseFragment).sendAudio(audios, caption, notify, scheduleDate)); @@ -1857,10 +1862,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N TLRPC.Chat currentChat = chatActivity.getCurrentChat(); audioLayout.setMaxSelectedFiles(currentChat != null && !ChatObject.hasAdminRights(currentChat) && currentChat.slowmode_enabled || editingMessageObject != null ? 1 : -1); } - showLayout(audioLayout); + if (show) { + showLayout(audioLayout); + } } - private void openDocumentsLayout() { + private void openDocumentsLayout(boolean show) { if (documentLayout == null) { layouts[4] = documentLayout = new ChatAttachAlertDocumentLayout(this, getContext(), false); documentLayout.setDelegate(new ChatAttachAlertDocumentLayout.DocumentSelectActivityDelegate() { @@ -1893,7 +1900,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N @Override public void startMusicSelectActivity() { - openAudioLayout(); + openAudioLayout(true); } }); } @@ -1905,7 +1912,9 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N documentLayout.setMaxSelectedFiles(maxSelectedPhotos); documentLayout.setCanSelectOnlyImageFiles(true); } - showLayout(documentLayout); + if (show) { + showLayout(documentLayout); + } } private boolean showCommentTextView(boolean show, boolean animated) { @@ -1923,7 +1932,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (show) { frameLayout2.setVisibility(View.VISIBLE); writeButtonContainer.setVisibility(View.VISIBLE); - } else { + if (!typeButtonsAvailable) { + shadow.setVisibility(View.VISIBLE); + } + } else if (typeButtonsAvailable) { buttonsRecyclerView.setVisibility(View.VISIBLE); } if (animated) { @@ -1940,9 +1952,12 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N animators.add(ObjectAnimator.ofFloat(frameLayout2, View.TRANSLATION_Y, show ? 0.0f : AndroidUtilities.dp(48))); animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36))); animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); - } else { + } else if (typeButtonsAvailable) { animators.add(ObjectAnimator.ofFloat(buttonsRecyclerView, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); animators.add(ObjectAnimator.ofFloat(shadow, View.TRANSLATION_Y, show ? AndroidUtilities.dp(36) : 0)); + } else { + shadow.setTranslationY(AndroidUtilities.dp(36)); + animators.add(ObjectAnimator.ofFloat(shadow, View.ALPHA, show ? 1.0f : 0.0f)); } commentsAnimator.playTogether(animators); @@ -1955,7 +1970,10 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (!show) { frameLayout2.setVisibility(View.INVISIBLE); writeButtonContainer.setVisibility(View.INVISIBLE); - } else { + if (!typeButtonsAvailable) { + shadow.setVisibility(View.INVISIBLE); + } + } else if (typeButtonsAvailable) { buttonsRecyclerView.setVisibility(View.INVISIBLE); } commentsAnimator = null; @@ -1982,13 +2000,19 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N frameLayout2.setTranslationY(show ? 0.0f : AndroidUtilities.dp(48)); shadow.setTranslationY(show ? AndroidUtilities.dp(36) : AndroidUtilities.dp(48 + 36)); shadow.setAlpha(show ? 1.0f : 0.0f); - } else { + } else if (typeButtonsAvailable) { buttonsRecyclerView.setTranslationY(show ? AndroidUtilities.dp(36) : 0); shadow.setTranslationY(show ? AndroidUtilities.dp(36) : 0); + } else { + shadow.setTranslationY(AndroidUtilities.dp(36)); + shadow.setAlpha(show ? 1.0f : 0.0f); } if (!show) { frameLayout2.setVisibility(View.INVISIBLE); writeButtonContainer.setVisibility(View.INVISIBLE); + if (!typeButtonsAvailable) { + shadow.setVisibility(View.INVISIBLE); + } } } return true; @@ -2067,9 +2091,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N setFocusable(true); editText.requestFocus(); if (showKeyboard) { - AndroidUtilities.runOnUIThread(() -> { - AndroidUtilities.showKeyboard(editText); - }); + AndroidUtilities.runOnUIThread(() -> AndroidUtilities.showKeyboard(editText)); } }, keyboardVisible ? 200 : 0); } @@ -2284,14 +2306,15 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N actionBarAnimation = null; } boolean needsSearchItem = avatarSearch || currentAttachLayout == photoLayout && !menuShowed && baseFragment instanceof ChatActivity && ((ChatActivity) baseFragment).allowSendGifs(); + boolean needMoreItem = avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout && mediaEnabled; if (show) { if (needsSearchItem) { searchItem.setVisibility(View.VISIBLE); } - if (avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout) { + if (needMoreItem) { selectedMenuItem.setVisibility(View.VISIBLE); } - } else if (avatarPicker == 0) { + } else if (typeButtonsAvailable) { buttonsRecyclerView.setVisibility(View.VISIBLE); } if (animated) { @@ -2303,7 +2326,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (needsSearchItem) { animators.add(ObjectAnimator.ofFloat(searchItem, View.ALPHA, show ? 1.0f : 0.0f)); } - if (avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout) { + if (needMoreItem) { animators.add(ObjectAnimator.ofFloat(selectedMenuItem, View.ALPHA, show ? 1.0f : 0.0f)); } actionBarAnimation.playTogether(animators); @@ -2312,7 +2335,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void onAnimationEnd(Animator animation) { if (actionBarAnimation != null) { if (show) { - if (avatarPicker == 0) { + if (typeButtonsAvailable) { buttonsRecyclerView.setVisibility(View.INVISIBLE); } } else { @@ -2332,7 +2355,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N actionBarAnimation.start(); } else { if (show) { - if (avatarPicker == 0) { + if (typeButtonsAvailable) { buttonsRecyclerView.setVisibility(View.INVISIBLE); } } @@ -2341,7 +2364,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N if (needsSearchItem) { searchItem.setAlpha(show ? 1.0f : 0.0f); } - if (avatarPicker != 0 || !menuShowed && currentAttachLayout == photoLayout) { + if (needMoreItem) { selectedMenuItem.setAlpha(show ? 1.0f : 0.0f); } if (!show) { @@ -2482,7 +2505,30 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N commentTextView.hidePopup(true); enterCommentEventSent = false; setFocusable(false); - if (currentAttachLayout != photoLayout) { + ChatAttachAlert.AttachAlertLayout layoutToSet; + if (editingMessageObject != null && editingMessageObject.hasValidGroupId() && (editingMessageObject.isMusic() || editingMessageObject.isDocument())) { + if (editingMessageObject.isMusic()) { + openAudioLayout(false); + layoutToSet = audioLayout; + selectedId = 3; + } else { + openDocumentsLayout(false); + layoutToSet = documentLayout; + selectedId = 4; + } + typeButtonsAvailable = false; + buttonsRecyclerView.setVisibility(View.GONE); + shadow.setVisibility(View.INVISIBLE); + } else { + layoutToSet = photoLayout; + typeButtonsAvailable = avatarPicker == 0; + selectedId = 1; + if (typeButtonsAvailable) { + buttonsRecyclerView.setVisibility(View.VISIBLE); + shadow.setVisibility(View.VISIBLE); + } + } + if (currentAttachLayout != layoutToSet) { if (actionBar.isSearchFieldVisible()) { actionBar.closeSearchField(); } @@ -2490,18 +2536,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N currentAttachLayout.onHide(); currentAttachLayout.setVisibility(View.GONE); currentAttachLayout.onHidden(); - currentAttachLayout = photoLayout; + currentAttachLayout = layoutToSet; setAllowNestedScroll(true); if (currentAttachLayout.getParent() == null) { containerView.addView(currentAttachLayout, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); } - selectedId = 1; - photoLayout.setAlpha(1.0f); - photoLayout.setVisibility(View.VISIBLE); - photoLayout.onShow(); - photoLayout.onShown(); - actionBar.setVisibility(View.VISIBLE); - actionBarShadow.setVisibility(View.VISIBLE); + layoutToSet.setAlpha(1.0f); + layoutToSet.setVisibility(View.VISIBLE); + layoutToSet.onShow(); + layoutToSet.onShown(); + actionBar.setVisibility(layoutToSet.needsActionBar() != 0 ? View.VISIBLE : View.INVISIBLE); + actionBarShadow.setVisibility(actionBar.getVisibility()); } updateCountButton(0); @@ -2536,6 +2581,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } currentAttachLayout.onOpenAnimationEnd(); AndroidUtilities.makeAccessibilityAnnouncement(LocaleController.getString("AccDescrAttachButton", R.string.AccDescrAttachButton)); + openTransitionFinished = true; } @Override @@ -2558,6 +2604,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N avatarPicker = type; avatarSearch = search; if (avatarPicker != 0) { + typeButtonsAvailable = false; buttonsRecyclerView.setVisibility(View.GONE); shadow.setVisibility(View.GONE); if (avatarPicker == 2) { @@ -2565,6 +2612,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N } else { selectedTextView.setText(LocaleController.getString("ChoosePhoto", R.string.ChoosePhoto)); } + } else { + typeButtonsAvailable = true; } } @@ -2680,9 +2729,17 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N galleryButton = buttonsCount++; documentButton = buttonsCount++; } else if (editingMessageObject != null) { - galleryButton = buttonsCount++; - documentButton = buttonsCount++; - musicButton = buttonsCount++; + if ((editingMessageObject.isMusic() || editingMessageObject.isDocument()) && editingMessageObject.hasValidGroupId()) { + if (editingMessageObject.isMusic()) { + musicButton = buttonsCount++; + } else { + documentButton = buttonsCount++; + } + } else { + galleryButton = buttonsCount++; + documentButton = buttonsCount++; + musicButton = buttonsCount++; + } } else { if (mediaEnabled) { galleryButton = buttonsCount++; @@ -2801,4 +2858,8 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N public void setAllowNestedScroll(boolean allowNestedScroll) { this.allowNestedScroll = allowNestedScroll; } + + public BaseFragment getBaseFragment() { + return baseFragment; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java index 18def36dc..cd0740323 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertAudioLayout.java @@ -81,6 +81,7 @@ public class ChatAttachAlertAudioLayout extends ChatAttachAlert.AttachAlertLayou private boolean ignoreLayout; private ArrayList audioEntries = new ArrayList<>(); + private ArrayList selectedAudiosOrder = new ArrayList<>(); private LongSparseArray selectedAudios = new LongSparseArray<>(); private AudioSelectDelegate delegate; @@ -371,6 +372,7 @@ public class ChatAttachAlertAudioLayout extends ChatAttachAlert.AttachAlertLayou @Override void onHidden() { selectedAudios.clear(); + selectedAudiosOrder.clear(); } @Override @@ -463,6 +465,7 @@ public class ChatAttachAlertAudioLayout extends ChatAttachAlert.AttachAlertLayou boolean add; if (selectedAudios.indexOfKey(audioEntry.id) >= 0) { selectedAudios.remove(audioEntry.id); + selectedAudiosOrder.remove(audioEntry); audioCell.setChecked(false, true); add = false; } else { @@ -471,6 +474,7 @@ public class ChatAttachAlertAudioLayout extends ChatAttachAlert.AttachAlertLayou return; } selectedAudios.put(audioEntry.id, audioEntry); + selectedAudiosOrder.add(audioEntry); audioCell.setChecked(true, true); add = true; } @@ -489,8 +493,8 @@ public class ChatAttachAlertAudioLayout extends ChatAttachAlert.AttachAlertLayou } sendPressed = true; ArrayList audios = new ArrayList<>(); - for (int a = 0; a < selectedAudios.size(); a++) { - audios.add(selectedAudios.valueAt(a).messageObject); + for (int a = 0; a < selectedAudiosOrder.size(); a++) { + audios.add(selectedAudiosOrder.get(a).messageObject); } delegate.didSelectAudio(audios, parentAlert.commentTextView.getText().toString(), notify, scheduleDate); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java index ad7448802..cc977f646 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertDocumentLayout.java @@ -103,6 +103,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa private ArrayList history = new ArrayList<>(); private DocumentSelectActivityDelegate delegate; private HashMap selectedFiles = new HashMap<>(); + private ArrayList selectedFilesOrder = new ArrayList<>(); private boolean scrolling; private ArrayList recentItems = new ArrayList<>(); private int maxSelectedFiles = -1; @@ -519,7 +520,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa return; } sendPressed = true; - ArrayList files = new ArrayList<>(selectedFiles.keySet()); + ArrayList files = new ArrayList<>(selectedFilesOrder); delegate.didSelectFiles(files, parentAlert.commentTextView.getText().toString(), notify, scheduleDate); parentAlert.dismiss(); } @@ -532,6 +533,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa boolean add; if (selectedFiles.containsKey(path)) { selectedFiles.remove(path); + selectedFilesOrder.remove(path); add = false; } else { if (!item.file.canRead()) { @@ -554,6 +556,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa return false; } selectedFiles.put(path, item); + selectedFilesOrder.add(path); add = true; } scrolling = false; @@ -694,6 +697,7 @@ public class ChatAttachAlertDocumentLayout extends ChatAttachAlert.AttachAlertLa @Override void onShow() { selectedFiles.clear(); + selectedFilesOrder.clear(); history.clear(); listRoots(); updateSearchButton(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java index 14714d194..eb17b406f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertLocationLayout.java @@ -17,6 +17,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -156,6 +157,7 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa private FrameLayout lastPressedMarkerView; private boolean checkPermission = true; + private boolean checkBackgroundPermission = true; private boolean searching; private boolean searchWas; @@ -1132,10 +1134,23 @@ public class ChatAttachAlertLocationLayout extends ChatAttachAlert.AttachAlertLa animatorSet.start(); } - private void openShareLiveLocation() { + public void openShareLiveLocation() { if (delegate == null || getParentActivity() == null || myLocation == null) { return; } + if (checkBackgroundPermission && Build.VERSION.SDK_INT >= 29) { + Activity activity = getParentActivity(); + if (activity != null) { + checkBackgroundPermission = false; + SharedPreferences preferences = MessagesController.getGlobalMainSettings(); + int lastTime = preferences.getInt("backgroundloc", 0); + if (Math.abs(System.currentTimeMillis() / 1000 - lastTime) > 24 * 60 * 60 && activity.checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) { + preferences.edit().putInt("backgroundloc", (int) (System.currentTimeMillis() / 1000)).commit(); + AlertsCreator.createBackgroundLocationPermissionDialog(activity, getMessagesController().getUser(getUserConfig().getClientUserId()), this::openShareLiveLocation).show(); + return; + } + } + } TLRPC.User user = null; if ((int) dialogId > 0) { user = parentAlert.baseFragment.getMessagesController().getUser((int) dialogId); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java index a61497964..b9b85f677 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java @@ -2063,8 +2063,11 @@ public class ChatAttachAlertPhotoLayout extends ChatAttachAlert.AttachAlertLayou } float topLocal = child.getY() + gridView.getY() + getY(); - float top = topLocal + parentAlert.getSheetContainer().getY(); + float top = topLocal + parentAlert.getSheetContainer().getY(); float left = child.getX() + gridView.getX() + getX() + parentAlert.getSheetContainer().getX(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + left -= getRootWindowInsets().getSystemWindowInsetLeft(); + } float maxY = (Build.VERSION.SDK_INT >= 21 && !parentAlert.inBubbleMode ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight(); if (topLocal < maxY) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java index 0b9dd9f53..e40d3b056 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -74,13 +74,13 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent avatarImageView = new BackupImageView(context); if (parentFragment != null) { sharedMediaPreloader = new SharedMediaLayout.SharedMediaPreloader(chatActivity); - if (parentFragment.isThreadChat()) { + if (parentFragment.isThreadChat() || parentFragment.getChatMode() == 2) { avatarImageView.setVisibility(GONE); } } avatarImageView.setRoundRadius(AndroidUtilities.dp(21)); addView(avatarImageView); - if (parentFragment != null && !parentFragment.isInScheduleMode() && !UserObject.isReplyUser(parentFragment.getCurrentUser())) { + if (parentFragment != null && parentFragment.getChatMode() == 0 && !UserObject.isReplyUser(parentFragment.getCurrentUser())) { avatarImageView.setOnClickListener(v -> openProfile(true)); } @@ -109,17 +109,17 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent timeItem.setContentDescription(LocaleController.getString("SetTimer", R.string.SetTimer)); } - if (parentFragment != null && !parentFragment.isInScheduleMode()) { + if (parentFragment != null && parentFragment.getChatMode() == 0) { if (!parentFragment.isThreadChat() && !UserObject.isReplyUser(parentFragment.getCurrentUser())) { setOnClickListener(v -> openProfile(false)); } TLRPC.Chat chat = parentFragment.getCurrentChat(); - statusDrawables[0] = new TypingDotsDrawable(); - statusDrawables[1] = new RecordStatusDrawable(); - statusDrawables[2] = new SendingFileDrawable(); - statusDrawables[3] = new PlayingGameDrawable(); - statusDrawables[4] = new RoundStatusDrawable(); + statusDrawables[0] = new TypingDotsDrawable(false); + statusDrawables[1] = new RecordStatusDrawable(false); + statusDrawables[2] = new SendingFileDrawable(false); + statusDrawables[3] = new PlayingGameDrawable(false); + statusDrawables[4] = new RoundStatusDrawable(false); for (int a = 0; a < statusDrawables.length; a++) { statusDrawables[a].setIsChat(chat != null); } @@ -309,14 +309,14 @@ public class ChatAvatarContainer extends FrameLayout implements NotificationCent return; } TLRPC.User user = parentFragment.getCurrentUser(); - if (UserObject.isUserSelf(user) || UserObject.isReplyUser(user) || parentFragment.isInScheduleMode()) { + if (UserObject.isUserSelf(user) || UserObject.isReplyUser(user) || parentFragment.getChatMode() != 0) { if (subtitleTextView.getVisibility() != GONE) { subtitleTextView.setVisibility(GONE); } return; } TLRPC.Chat chat = parentFragment.getCurrentChat(); - CharSequence printString = MessagesController.getInstance(currentAccount).getPrintingString(parentFragment.getDialogId(), parentFragment.getThreadId()); + CharSequence printString = MessagesController.getInstance(currentAccount).getPrintingString(parentFragment.getDialogId(), parentFragment.getThreadId(), false); if (printString != null) { printString = TextUtils.replace(printString, new String[]{"..."}, new String[]{""}); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java index 142f5220f..5cfc7d680 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBox2.java @@ -51,7 +51,7 @@ public class CheckBox2 extends View { } public void setDrawBackgroundAsArc(int type) { - checkBoxBase.setDrawBackgroundAsArc(type); + checkBoxBase.setBackgroundType(type); } public float getProgress() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java index cad339b3a..debc97ddb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxBase.java @@ -6,6 +6,8 @@ import android.animation.ObjectAnimator; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; @@ -55,7 +57,7 @@ public class CheckBoxBase { private boolean useDefaultCheck; private boolean drawUnchecked = true; - private int drawBackgroundAsArc; + private int backgroundType; private float size; @@ -63,6 +65,8 @@ public class CheckBoxBase { private ProgressDelegate progressDelegate; + private Theme.MessageDrawable messageDrawable; + public interface ProgressDelegate { void setProgress(float progress); } @@ -151,9 +155,11 @@ public class CheckBoxBase { enabled = value; } - public void setDrawBackgroundAsArc(int type) { - drawBackgroundAsArc = type; - if (type == 4 || type == 5) { + public void setBackgroundType(int type) { + backgroundType = type; + if (type == 12 || type == 13) { + backgroundPaint.setStrokeWidth(AndroidUtilities.dp(1)); + } else if (type == 4 || type == 5) { backgroundPaint.setStrokeWidth(AndroidUtilities.dp(1.9f)); if (type == 5) { checkPaint.setStrokeWidth(AndroidUtilities.dp(1.5f)); @@ -196,6 +202,10 @@ public class CheckBoxBase { checkColorKey = check; } + public void setBackgroundDrawable(Theme.MessageDrawable drawable) { + messageDrawable = drawable; + } + public void setUseDefaultCheck(boolean value) { useDefaultCheck = value; } @@ -243,8 +253,12 @@ public class CheckBoxBase { drawBitmap.eraseColor(0); float rad = AndroidUtilities.dp(size / 2); float outerRad = rad; - if (drawBackgroundAsArc != 0 && drawBackgroundAsArc != 11) { - outerRad -= AndroidUtilities.dp(0.2f); + if (backgroundType == 12 || backgroundType == 13) { + rad = outerRad = AndroidUtilities.dp(10); + } else { + if (backgroundType != 0 && backgroundType != 11) { + outerRad -= AndroidUtilities.dp(0.2f); + } } float roundProgress = progress >= 0.5f ? 1.0f : progress / 0.5f; @@ -254,10 +268,14 @@ public class CheckBoxBase { if (backgroundColorKey != null) { if (drawUnchecked) { - if (drawBackgroundAsArc == 6 || drawBackgroundAsArc == 7) { + if (backgroundType == 12 || backgroundType == 13) { + paint.setColor(Theme.getColor(backgroundColorKey)); + paint.setAlpha((int) (255 * backgroundAlpha)); + backgroundPaint.setColor(Theme.getColor(checkColorKey)); + } else if (backgroundType == 6 || backgroundType == 7) { paint.setColor(Theme.getColor(background2ColorKey)); backgroundPaint.setColor(Theme.getColor(checkColorKey)); - } else if (drawBackgroundAsArc == 10) { + } else if (backgroundType == 10) { backgroundPaint.setColor(Theme.getColor(background2ColorKey)); } else { paint.setColor((Theme.getServiceMessageColor() & 0x00ffffff) | 0x28000000); @@ -269,7 +287,7 @@ public class CheckBoxBase { } else { if (drawUnchecked) { paint.setColor(Color.argb((int) (25 * backgroundAlpha), 0, 0, 0)); - if (drawBackgroundAsArc == 8) { + if (backgroundType == 8) { backgroundPaint.setColor(Theme.getColor(background2ColorKey)); } else { backgroundPaint.setColor(AndroidUtilities.getOffsetColor(0xffffffff, Theme.getColor(checkColorKey), progress, backgroundAlpha)); @@ -280,9 +298,11 @@ public class CheckBoxBase { } if (drawUnchecked) { - if (drawBackgroundAsArc == 8 || drawBackgroundAsArc == 10) { + if (backgroundType == 12 || backgroundType == 13) { + //draw nothing + } else if (backgroundType == 8 || backgroundType == 10) { canvas.drawCircle(cx, cy, rad - AndroidUtilities.dp(1.5f), backgroundPaint); - } else if (drawBackgroundAsArc == 6 || drawBackgroundAsArc == 7) { + } else if (backgroundType == 6 || backgroundType == 7) { canvas.drawCircle(cx, cy, rad - AndroidUtilities.dp(1), paint); canvas.drawCircle(cx, cy, rad - AndroidUtilities.dp(1.5f), backgroundPaint); } else { @@ -290,17 +310,30 @@ public class CheckBoxBase { } } paint.setColor(Theme.getColor(checkColorKey)); - if (drawBackgroundAsArc != 7 && drawBackgroundAsArc != 8 && drawBackgroundAsArc != 9 && drawBackgroundAsArc != 10) { - if (drawBackgroundAsArc == 0 || drawBackgroundAsArc == 11) { + if (backgroundType != 7 && backgroundType != 8 && backgroundType != 9 && backgroundType != 10) { + if (backgroundType == 12 || backgroundType == 13) { + backgroundPaint.setStyle(Paint.Style.FILL); + if (messageDrawable != null && messageDrawable.hasGradient()) { + LinearGradient shader = messageDrawable.getGradientShader(); + Matrix matrix = messageDrawable.getMatrix(); + matrix.setTranslate(0, -messageDrawable.getTopY() + bounds.top); + shader.setLocalMatrix(matrix); + backgroundPaint.setShader(shader); + } else { + backgroundPaint.setShader(null); + } + canvas.drawCircle(cx, cy, (rad - AndroidUtilities.dp(1)) * backgroundAlpha, backgroundPaint); + backgroundPaint.setStyle(Paint.Style.STROKE); + } else if (backgroundType == 0 || backgroundType == 11) { canvas.drawCircle(cx, cy, rad, backgroundPaint); } else { rect.set(cx - outerRad, cy - outerRad, cx + outerRad, cy + outerRad); int startAngle; int sweepAngle; - if (drawBackgroundAsArc == 6) { + if (backgroundType == 6) { startAngle = 0; sweepAngle = (int) (-360 * progress); - } else if (drawBackgroundAsArc == 1) { + } else if (backgroundType == 1) { startAngle = -90; sweepAngle = (int) (-270 * progress); } else { @@ -308,7 +341,7 @@ public class CheckBoxBase { sweepAngle = (int) (270 * progress); } - if (drawBackgroundAsArc == 6) { + if (backgroundType == 6) { int color = Theme.getColor(Theme.key_dialogBackground); int alpha = Color.alpha(color); backgroundPaint.setColor(color); @@ -318,19 +351,17 @@ public class CheckBoxBase { alpha = Color.alpha(color); backgroundPaint.setColor(color); backgroundPaint.setAlpha((int) (alpha * progress)); - canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); - } else { - canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); } + canvas.drawArc(rect, startAngle, sweepAngle, false, backgroundPaint); } } if (roundProgress > 0) { float checkProgress = progress < 0.5f ? 0.0f : (progress - 0.5f) / 0.5f; - if (drawBackgroundAsArc == 9) { + if (backgroundType == 9) { paint.setColor(Theme.getColor(background2ColorKey)); - } else if (drawBackgroundAsArc == 11 || drawBackgroundAsArc == 6 || drawBackgroundAsArc == 7 || drawBackgroundAsArc == 10 || !drawUnchecked && backgroundColorKey != null) { + } else if (backgroundType == 11 || backgroundType == 6 || backgroundType == 7 || backgroundType == 10 || !drawUnchecked && backgroundColorKey != null) { paint.setColor(Theme.getColor(backgroundColorKey)); } else { paint.setColor(Theme.getColor(enabled ? Theme.key_checkbox : Theme.key_checkboxDisabled)); @@ -341,9 +372,14 @@ public class CheckBoxBase { checkPaint.setColor(Theme.getColor(Theme.key_checkboxCheck)); } - rad -= AndroidUtilities.dp(0.5f); - bitmapCanvas.drawCircle(drawBitmap.getWidth() / 2, drawBitmap.getHeight() / 2, rad, paint); - bitmapCanvas.drawCircle(drawBitmap.getWidth() / 2, drawBitmap.getWidth() / 2, rad * (1.0f - roundProgress), eraser); + if (backgroundType == 12 || backgroundType == 13) { + paint.setAlpha((int) (255 * roundProgress)); + bitmapCanvas.drawCircle(drawBitmap.getWidth() / 2, drawBitmap.getHeight() / 2, rad * roundProgress, paint); + } else { + rad -= AndroidUtilities.dp(0.5f); + bitmapCanvas.drawCircle(drawBitmap.getWidth() / 2, drawBitmap.getHeight() / 2, rad, paint); + bitmapCanvas.drawCircle(drawBitmap.getWidth() / 2, drawBitmap.getHeight() / 2, rad * (1.0f - roundProgress), eraser); + } canvas.drawBitmap(drawBitmap, cx - drawBitmap.getWidth() / 2, cy - drawBitmap.getHeight() / 2, null); if (checkProgress != 0) { @@ -377,7 +413,7 @@ public class CheckBoxBase { } else { path.reset(); - float scale = drawBackgroundAsArc == 5 ? 0.8f : 1.0f; + float scale = backgroundType == 5 ? 0.8f : 1.0f; float checkSide = AndroidUtilities.dp(9 * scale) * checkProgress; float smallCheckSide = AndroidUtilities.dp(4 * scale) * checkProgress; int x = cx - AndroidUtilities.dp(1.5f); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EllipsizeSpanAnimator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EllipsizeSpanAnimator.java index a99592ab7..3c283d5b5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EllipsizeSpanAnimator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EllipsizeSpanAnimator.java @@ -9,8 +9,6 @@ import android.text.TextPaint; import android.text.style.CharacterStyle; import android.view.View; -import com.google.android.exoplayer2.util.Log; - import java.util.ArrayList; public class EllipsizeSpanAnimator { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastGridLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastGridLayoutManager.java index dd5704639..66c7a9aa1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastGridLayoutManager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FillLastGridLayoutManager.java @@ -47,15 +47,18 @@ public class FillLastGridLayoutManager extends GridLayoutManager { int count = adapter.getItemCount() - 1; int allHeight = 0; final SpanSizeLookup spanSizeLookup = getSpanSizeLookup(); + boolean add = true; for (int a = 0; a < count; a++) { final int spanSize = spanSizeLookup.getSpanSize(a); spanCounter += spanSize; - if (spanSize == spanCount || spanCounter > spanCount) { - spanCounter = 0; - } else if (spanCounter != 1) { + spanCounter = spanSize; + add = true; + } + if (!add) { continue; } + add = false; int type = adapter.getItemViewType(a); RecyclerView.ViewHolder holder = heights.get(type, null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java new file mode 100644 index 000000000..4586ea899 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlickerLoadingView.java @@ -0,0 +1,262 @@ +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.SystemClock; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.ActionBar.Theme; + +public class FlickerLoadingView extends View { + + public final static int DIALOG_TYPE = 1; + public final static int PHOTOS_TYPE = 2; + public final static int FILES_TYPE = 3; + public final static int AUDIO_TYPE = 4; + public final static int LINKS_TYPE = 5; + + int gradientWidth; + LinearGradient gradient; + Paint paint = new Paint(); + private long lastUpdateTime; + private int totalTranslation; + private Matrix matrix; + RectF rectF = new RectF(); + int color0; + int color1; + private boolean showDate = true; + + private boolean isSingleCell; + + int viewType; + + public void setViewType(int type) { + this.viewType = type; + invalidate(); + } + + public void setIsSingleCell(boolean b) { + isSingleCell = b; + } + + public int getViewType() { + return viewType; + } + + public int getColumnsCount() { + return 2; + } + + public FlickerLoadingView(Context context) { + super(context); + matrix = new Matrix(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (isSingleCell) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getCellHeight(), MeasureSpec.EXACTLY)); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + protected void onDraw(Canvas canvas) { + int color0 = Theme.getColor(Theme.key_dialogBackground); + int color1 = Theme.getColor(Theme.key_windowBackgroundGray); + if (this.color1 != color1 || this.color0 != color0) { + this.color0 = color0; + this.color1 = color1; + if (isSingleCell) { + gradient = new LinearGradient(0, 0, gradientWidth = AndroidUtilities.dp(200), 0, new int[]{color1, color0, color0, color1}, new float[]{0.0f, 0.4f, 0.6f, 1f}, Shader.TileMode.CLAMP); + } else { + gradient = new LinearGradient(0, 0, 0, gradientWidth = AndroidUtilities.dp(600), new int[]{color1, color0, color0, color1}, new float[]{0.0f, 0.4f, 0.6f, 1f}, Shader.TileMode.CLAMP); + } + paint.setShader(gradient); + } + if (getViewType() == DIALOG_TYPE) { + int h = 0; + while (h < getMeasuredHeight()) { + int r = AndroidUtilities.dp(25); + canvas.drawCircle(checkRtl(AndroidUtilities.dp(9) + r), h + (AndroidUtilities.dp(78) >> 1), r, paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(20), AndroidUtilities.dp(140), h + AndroidUtilities.dp(28)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(42), AndroidUtilities.dp(260), h + AndroidUtilities.dp(50)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + if (showDate) { + rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(20), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(28)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + } + + h += getCellHeight(); + if (isSingleCell) { + break; + } + } + } else if (getViewType() == PHOTOS_TYPE) { + int photoWidth = (getMeasuredWidth() - (AndroidUtilities.dp(2) * (getColumnsCount() - 1))) / getColumnsCount(); + int h = 0; + while (h < getMeasuredHeight()) { + for (int i = 0; i < getColumnsCount(); i++) { + int x = i * (photoWidth + AndroidUtilities.dp(2)); + canvas.drawRect(x, h, x + photoWidth, h + photoWidth, paint); + } + h += photoWidth + AndroidUtilities.dp(2); + if (isSingleCell) { + break; + } + } + } else if (getViewType() == 3) { + int h = 0; + while (h < getMeasuredHeight()) { + rectF.set(AndroidUtilities.dp(12), h + AndroidUtilities.dp(8), AndroidUtilities.dp(52), h + AndroidUtilities.dp(48)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(260), h + AndroidUtilities.dp(42)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + if (showDate) { + rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + } + + h += getCellHeight(); + if (isSingleCell) { + break; + } + } + } else if (getViewType() == 4) { + int h = 0; + while (h < getMeasuredHeight()) { + int radius = AndroidUtilities.dp(44) >> 1; + canvas.drawCircle(checkRtl(AndroidUtilities.dp(12) + radius), h + AndroidUtilities.dp(6) + radius, radius, paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(260), h + AndroidUtilities.dp(42)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + if (showDate) { + rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + } + + h += getCellHeight(); + if (isSingleCell) { + break; + } + } + } else if (getViewType() == 5) { + int h = 0; + while (h < getMeasuredHeight()) { + rectF.set(AndroidUtilities.dp(10), h + AndroidUtilities.dp(11), AndroidUtilities.dp(62), h + AndroidUtilities.dp(11 + 52)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(268), h + AndroidUtilities.dp(42)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34 + 20), AndroidUtilities.dp(120 + 68), h + AndroidUtilities.dp(42 + 20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + + if (showDate) { + rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); + checkRtl(rectF); + canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); + } + + h += getCellHeight(); + if (isSingleCell) { + break; + } + } + } + + long newUpdateTime = SystemClock.elapsedRealtime(); + long dt = Math.abs(lastUpdateTime - newUpdateTime); + if (dt > 17) { + dt = 16; + } + lastUpdateTime = newUpdateTime; + if (isSingleCell) { + totalTranslation += dt * getMeasuredWidth() / 400.0f; + if (totalTranslation >= getMeasuredWidth() * 2) { + totalTranslation = -gradientWidth * 2; + } + matrix.setTranslate(totalTranslation, 0); + } else { + totalTranslation += dt * getMeasuredHeight() / 400.0f; + if (totalTranslation >= getMeasuredHeight() * 2) { + totalTranslation = -gradientWidth * 2; + } + matrix.setTranslate(0, totalTranslation); + } + gradient.setLocalMatrix(matrix); + invalidate(); + } + + private float checkRtl(float x) { + if (LocaleController.isRTL) { + return getMeasuredWidth() - x; + } + return x; + } + + private void checkRtl(RectF rectF) { + if (LocaleController.isRTL) { + rectF.left = getMeasuredWidth() - rectF.left; + rectF.right = getMeasuredWidth() - rectF.right; + } + } + + private int getCellHeight() { + if (getViewType() == DIALOG_TYPE) { + return AndroidUtilities.dp(78) + 1; + } else if (getViewType() == PHOTOS_TYPE) { + int photoWidth = (getMeasuredWidth() - (AndroidUtilities.dp(2) * (getColumnsCount() - 1))) / getColumnsCount(); + return photoWidth + AndroidUtilities.dp(2); + } else if (getViewType() == 3) { + return AndroidUtilities.dp(56) + 1; + } else if (getViewType() == 4) { + return AndroidUtilities.dp(56) + 1; + } else if (getViewType() == 5) { + return AndroidUtilities.dp(80); + } + return 0; + } + + public void showDate(boolean showDate) { + this.showDate = showDate; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java index 908e52f60..746357746 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FragmentContextView.java @@ -59,6 +59,7 @@ import java.util.ArrayList; public class FragmentContextView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { private ImageView playButton; + private PlayPauseDrawable playPauseDrawable; private TextView titleTextView; private AnimatorSet animatorSet; private BaseFragment fragment; @@ -122,12 +123,13 @@ public class FragmentContextView extends FrameLayout implements NotificationCent frameLayout.addView(selector, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); View shadow = new View(context); - shadow.setBackgroundResource(R.drawable.header_shadow); - addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.LEFT | Gravity.TOP, 0, 36, 0, 0)); + shadow.setBackgroundResource(R.drawable.blockpanel_shadow); + addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 2, Gravity.LEFT | Gravity.TOP, 0, 36, 0, 0)); playButton = new ImageView(context); playButton.setScaleType(ImageView.ScaleType.CENTER); playButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_inappPlayerPlayPause), PorterDuff.Mode.SRC_IN)); + playButton.setImageDrawable(playPauseDrawable = new PlayPauseDrawable(14)); if (Build.VERSION.SDK_INT >= 21) { playButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_inappPlayerPlayPause) & 0x19ffffff, 1, AndroidUtilities.dp(14))); } @@ -178,7 +180,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent closeButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_inappPlayerClose) & 0x19ffffff, 1, AndroidUtilities.dp(14))); } closeButton.setScaleType(ImageView.ScaleType.CENTER); - addView(closeButton, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + addView(closeButton, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP, 0, 0, 2, 0)); closeButton.setOnClickListener(v -> { if (currentStyle == 2) { AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); @@ -239,7 +241,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { args.putInt("chat_id", -lower_part); } } else { @@ -269,8 +271,6 @@ public class FragmentContextView extends FrameLayout implements NotificationCent break; } } - } else { - did = 0; } if (did != 0) { openSharingLocation(LocationController.getInstance(account).getSharingLocationInfo(did)); @@ -390,7 +390,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent playbackSpeedButton.setVisibility(VISIBLE); } closeButton.setContentDescription(LocaleController.getString("AccDescrClosePlayer", R.string.AccDescrClosePlayer)); - } else if (style == 2) { + } else { playButton.setLayoutParams(LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.LEFT, 8, 0, 0, 0)); titleTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 35 + 16, 0, 36, 0)); closeButton.setContentDescription(LocaleController.getString("AccDescrStopLiveLocation", R.string.AccDescrStopLiveLocation)); @@ -466,7 +466,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, AndroidUtilities.dp2(39)); + super.onMeasure(widthMeasureSpec, AndroidUtilities.dp2(38)); } @Override @@ -565,6 +565,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent if (fragment instanceof DialogsActivity) { String liveLocation = LocaleController.getString("LiveLocationContext", R.string.LiveLocationContext); String param; + String str; ArrayList infos = new ArrayList<>(); for (int a = 0; a < UserConfig.MAX_ACCOUNT_COUNT; a++) { infos.addAll(LocationController.getInstance(a).sharingLocationsUI); @@ -575,6 +576,7 @@ public class FragmentContextView extends FrameLayout implements NotificationCent if (lower_id > 0) { TLRPC.User user = MessagesController.getInstance(info.messageObject.currentAccount).getUser(lower_id); param = UserObject.getFirstName(user); + str = LocaleController.getString("AttachLiveLocationIsSharing", R.string.AttachLiveLocationIsSharing); } else { TLRPC.Chat chat = MessagesController.getInstance(info.messageObject.currentAccount).getChat(-lower_id); if (chat != null) { @@ -582,11 +584,13 @@ public class FragmentContextView extends FrameLayout implements NotificationCent } else { param = ""; } + str = LocaleController.getString("AttachLiveLocationIsSharingChat", R.string.AttachLiveLocationIsSharingChat); } } else { param = LocaleController.formatPluralString("Chats", infos.size()); + str = LocaleController.getString("AttachLiveLocationIsSharingChats", R.string.AttachLiveLocationIsSharingChats); } - String fullString = String.format(LocaleController.getString("AttachLiveLocationIsSharing", R.string.AttachLiveLocationIsSharing), liveLocation, param); + String fullString = String.format(str, liveLocation, param); int start = fullString.indexOf(liveLocation); SpannableStringBuilder stringBuilder = new SpannableStringBuilder(fullString); titleTextView.setEllipsize(TextUtils.TruncateAt.END); @@ -777,10 +781,10 @@ public class FragmentContextView extends FrameLayout implements NotificationCent setVisibility(VISIBLE); } if (MediaController.getInstance().isMessagePaused()) { - playButton.setImageResource(R.drawable.miniplayer_play); + playPauseDrawable.setPause(false, !create); playButton.setContentDescription(LocaleController.getString("AccActionPlay", R.string.AccActionPlay)); } else { - playButton.setImageResource(R.drawable.miniplayer_pause); + playPauseDrawable.setPause(true, !create); playButton.setContentDescription(LocaleController.getString("AccActionPause", R.string.AccActionPause)); } if (lastMessageObject != messageObject || prevStyle != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java index 33ca3665d..b6e35b7a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintView.java @@ -42,6 +42,8 @@ public class HintView extends FrameLayout { private boolean isTopArrow; private String overrideText; private int shownY; + private float translationY; + private float extraTranslationY; private int bottomOffset; private long showingDuration = 2000; @@ -105,6 +107,15 @@ public class HintView extends FrameLayout { } } + public void setExtraTranslationY(float value) { + extraTranslationY = value; + setTranslationY(extraTranslationY + translationY); + } + + public float getBaseTranslationY() { + return translationY; + } + public boolean showForMessageCell(ChatMessageCell cell, boolean animated) { return showForMessageCell(cell, null, 0, 0, animated); } @@ -185,9 +196,9 @@ public class HintView extends FrameLayout { int parentWidth = parentView.getMeasuredWidth(); if (isTopArrow) { - setTranslationY(AndroidUtilities.dp(44)); + setTranslationY(extraTranslationY + (translationY = AndroidUtilities.dp(44))); } else { - setTranslationY(top - getMeasuredHeight()); + setTranslationY(extraTranslationY + (translationY = top - getMeasuredHeight())); } int iconX = cell.getLeft() + centerX; int left = AndroidUtilities.dp(19); @@ -268,6 +279,8 @@ public class HintView extends FrameLayout { if (currentType == 4) { top += AndroidUtilities.dp(4); + } else if (currentType == 6) { + top += view.getMeasuredHeight() + getMeasuredHeight() + AndroidUtilities.dp(10); } int centerX; @@ -289,10 +302,10 @@ public class HintView extends FrameLayout { top -= bottomOffset; int parentWidth = parentView.getMeasuredWidth(); - if (isTopArrow) { - setTranslationY(AndroidUtilities.dp(44)); + if (isTopArrow && currentType != 6) { + setTranslationY(extraTranslationY + (translationY = AndroidUtilities.dp(44))); } else { - setTranslationY(top - getMeasuredHeight()); + setTranslationY(extraTranslationY + (translationY = top - getMeasuredHeight())); } final int offset; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java index 64a2449fa..22e616013 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MediaActionDrawable.java @@ -268,7 +268,7 @@ public class MediaActionDrawable extends Drawable { if (messageDrawable != null && messageDrawable.hasGradient() && !hasOverlayImage) { LinearGradient shader = messageDrawable.getGradientShader(); Matrix matrix = messageDrawable.getMatrix(); - matrix.postTranslate(0, bounds.top); + matrix.setTranslate(0, -messageDrawable.getTopY() + bounds.top); shader.setLocalMatrix(matrix); paint.setShader(shader); paint2.setShader(shader); @@ -715,13 +715,18 @@ public class MediaActionDrawable extends Drawable { progress1 = 1.0f; progress2 = 0.0f; } + paint.setAlpha(255); } else { progress1 = 0.0f; progress2 = 1.0f; + if (nextIcon != ICON_CHECK) { + paint.setAlpha((int) (255 * (1.0f - transitionProgress))); + } else { + paint.setAlpha(255); + } } int y = cy + AndroidUtilities.dp(7); int x = cx - AndroidUtilities.dp(3); - paint.setAlpha(255); if (progress1 < 1) { canvas.drawLine(x - AndroidUtilities.dp(6), y - AndroidUtilities.dp(6), x - AndroidUtilities.dp(6) * progress1, y - AndroidUtilities.dp(6) * progress1, paint); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/MsgClockDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/MsgClockDrawable.java new file mode 100644 index 000000000..8c500f66e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/MsgClockDrawable.java @@ -0,0 +1,85 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; + +public class MsgClockDrawable extends Drawable { + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + int alpha = 255; + int colorAlpha = 255; + + long startTime; + + public MsgClockDrawable() { + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStrokeWidth(AndroidUtilities.dp(1f)); + startTime = System.currentTimeMillis(); + } + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + int r = Math.min(bounds.width(), bounds.height()); + canvas.drawCircle(bounds.centerX(), bounds.centerY(), (r >> 1) - AndroidUtilities.dp(0.5f), paint); + + long currentTime = System.currentTimeMillis(); + float rotateTime = 1500; + float rotateHourTime = rotateTime * 3; + + canvas.save(); + canvas.rotate(360 * ((currentTime - startTime) % rotateTime) / rotateTime, bounds.centerX(), bounds.centerY()); + canvas.drawLine(bounds.centerX(), bounds.centerY(), bounds.centerX(), bounds.centerY() - AndroidUtilities.dp(3), paint); + canvas.restore(); + + canvas.save(); + canvas.rotate(360 * ((currentTime - startTime) % rotateHourTime) / rotateHourTime, bounds.centerX(), bounds.centerY()); + canvas.drawLine(bounds.centerX(), bounds.centerY(), bounds.centerX() + AndroidUtilities.dp(2.3f), bounds.centerY(), paint); + canvas.restore(); + } + + public void setColor(int color) { + colorAlpha = Color.alpha(color); + paint.setColor(color); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(12); + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(12); + } + + @Override + public void setAlpha(int i) { + if (alpha != i) { + alpha = i; + paint.setAlpha((int) (alpha * (colorAlpha / 255f))); + } + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java index 99b0f548a..39e47a777 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java @@ -35,6 +35,7 @@ public class NumberTextView extends View { private ObjectAnimator animator; private float progress = 0.0f; private int currentNumber = 1; + private boolean addNumber; public NumberTextView(Context context) { super(context); @@ -54,6 +55,10 @@ public class NumberTextView extends View { return progress; } + public void setAddNumber() { + addNumber = true; + } + public void setNumber(int number, boolean animated) { if (currentNumber == number && animated) { return; @@ -65,9 +70,18 @@ public class NumberTextView extends View { oldLetters.clear(); oldLetters.addAll(letters); letters.clear(); - String oldText = String.format(Locale.US, "%d", currentNumber); - String text = String.format(Locale.US, "%d", number); - boolean forwardAnimation = number > currentNumber; + String oldText; + String text; + boolean forwardAnimation; + if (addNumber) { + oldText = String.format(Locale.US, "#%d", currentNumber); + text = String.format(Locale.US, "#%d", number); + forwardAnimation = number < currentNumber; + } else { + oldText = String.format(Locale.US, "%d", currentNumber); + text = String.format(Locale.US, "%d", number); + forwardAnimation = number > currentNumber; + } currentNumber = number; progress = 0; for (int a = 0; a < text.length(); a++) { @@ -83,7 +97,7 @@ public class NumberTextView extends View { } if (animated && !oldLetters.isEmpty()) { animator = ObjectAnimator.ofFloat(this, "progress", forwardAnimation ? -1 : 1, 0); - animator.setDuration(150); + animator.setDuration(addNumber ? 180 : 150); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -121,6 +135,7 @@ public class NumberTextView extends View { return; } float height = letters.get(0).getHeight(); + float translationHeight = addNumber ? AndroidUtilities.dp(4) : height; canvas.save(); canvas.translate(getPaddingLeft(), (getMeasuredHeight() - height) / 2); int count = Math.max(letters.size(), oldLetters.size()); @@ -132,12 +147,12 @@ public class NumberTextView extends View { if (old != null) { textPaint.setAlpha((int) (255 * progress)); canvas.save(); - canvas.translate(0, (progress - 1.0f) * height); + canvas.translate(0, (progress - 1.0f) * translationHeight); old.draw(canvas); canvas.restore(); if (layout != null) { textPaint.setAlpha((int) (255 * (1.0f - progress))); - canvas.translate(0, progress * height); + canvas.translate(0, progress * translationHeight); } } else { textPaint.setAlpha(255); @@ -146,14 +161,14 @@ public class NumberTextView extends View { if (old != null) { textPaint.setAlpha((int) (255 * -progress)); canvas.save(); - canvas.translate(0, (1.0f + progress) * height); + canvas.translate(0, (1.0f + progress) * translationHeight); old.draw(canvas); canvas.restore(); } if (layout != null) { if (a == count - 1 || old != null) { textPaint.setAlpha((int) (255 * (1.0f + progress))); - canvas.translate(0, progress * height); + canvas.translate(0, progress * translationHeight); } else { textPaint.setAlpha(255); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ColorPicker.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ColorPicker.java index cdf51c185..631b5ccbc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ColorPicker.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Paint/Views/ColorPicker.java @@ -150,7 +150,7 @@ public class ColorPicker extends FrameLayout { for (int i = 1; i < LOCATIONS.length; i++) { float value = LOCATIONS[i]; - if (value > location) { + if (value >= location) { leftIndex = i - 1; rightIndex = i; break; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PathAnimator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PathAnimator.java index 393700d65..78fb0efea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PathAnimator.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PathAnimator.java @@ -20,6 +20,7 @@ import java.util.ArrayList; public class PathAnimator { private Path path = new Path(); + private float pathTime = -1; private float scale; private float tx; private float ty; @@ -108,69 +109,72 @@ public class PathAnimator { } public void draw(Canvas canvas, Paint paint, float time) { - KeyFrame startKeyFrame = null; - KeyFrame endKeyFrame = null; - for (int a = 0, N = keyFrames.size(); a < N; a++) { - KeyFrame keyFrame = keyFrames.get(a); - if ((startKeyFrame == null || startKeyFrame.time < keyFrame.time) && keyFrame.time <= time) { - startKeyFrame = keyFrame; + if (pathTime != time) { + pathTime = time; + KeyFrame startKeyFrame = null; + KeyFrame endKeyFrame = null; + for (int a = 0, N = keyFrames.size(); a < N; a++) { + KeyFrame keyFrame = keyFrames.get(a); + if ((startKeyFrame == null || startKeyFrame.time < keyFrame.time) && keyFrame.time <= time) { + startKeyFrame = keyFrame; + } + if ((endKeyFrame == null || endKeyFrame.time > keyFrame.time) && keyFrame.time >= time) { + endKeyFrame = keyFrame; + } } - if ((endKeyFrame == null || endKeyFrame.time > keyFrame.time) && keyFrame.time >= time) { - endKeyFrame = keyFrame; + if (endKeyFrame == startKeyFrame) { + startKeyFrame = null; } - } - if (endKeyFrame == startKeyFrame) { - startKeyFrame = null; - } - if (startKeyFrame != null && endKeyFrame == null) { - endKeyFrame = startKeyFrame; - startKeyFrame = null; - } - if (endKeyFrame == null || startKeyFrame != null && startKeyFrame.commands.size() != endKeyFrame.commands.size()) { - return; - } - path.reset(); - for (int a = 0, N = endKeyFrame.commands.size(); a < N; a++) { - Object startCommand = startKeyFrame != null ? startKeyFrame.commands.get(a) : null; - Object endCommand = endKeyFrame.commands.get(a); - if (startCommand != null && startCommand.getClass() != endCommand.getClass()) { + if (startKeyFrame != null && endKeyFrame == null) { + endKeyFrame = startKeyFrame; + startKeyFrame = null; + } + if (endKeyFrame == null || startKeyFrame != null && startKeyFrame.commands.size() != endKeyFrame.commands.size()) { return; } - float progress; - if (startKeyFrame != null) { - progress = (time - startKeyFrame.time) / (endKeyFrame.time - startKeyFrame.time); - } else { - progress = 1.0f; - } - if (endCommand instanceof MoveTo) { - MoveTo end = (MoveTo) endCommand; - MoveTo start = (MoveTo) startCommand; - if (start != null) { - path.moveTo(AndroidUtilities.dp(start.x + (end.x - start.x) * progress), AndroidUtilities.dp(start.y + (end.y - start.y) * progress)); - } else { - path.moveTo(AndroidUtilities.dp(end.x), AndroidUtilities.dp(end.y)); + path.reset(); + for (int a = 0, N = endKeyFrame.commands.size(); a < N; a++) { + Object startCommand = startKeyFrame != null ? startKeyFrame.commands.get(a) : null; + Object endCommand = endKeyFrame.commands.get(a); + if (startCommand != null && startCommand.getClass() != endCommand.getClass()) { + return; } - } else if (endCommand instanceof LineTo) { - LineTo end = (LineTo) endCommand; - LineTo start = (LineTo) startCommand; - if (start != null) { - path.lineTo(AndroidUtilities.dp(start.x + (end.x - start.x) * progress), AndroidUtilities.dp(start.y + (end.y - start.y) * progress)); + float progress; + if (startKeyFrame != null) { + progress = (time - startKeyFrame.time) / (endKeyFrame.time - startKeyFrame.time); } else { - path.lineTo(AndroidUtilities.dp(end.x), AndroidUtilities.dp(end.y)); + progress = 1.0f; } - } else if (endCommand instanceof CurveTo) { - CurveTo end = (CurveTo) endCommand; - CurveTo start = (CurveTo) startCommand; - if (start != null) { - path.cubicTo(AndroidUtilities.dp(start.x1 + (end.x1 - start.x1) * progress), AndroidUtilities.dp(start.y1 + (end.y1 - start.y1) * progress), - AndroidUtilities.dp(start.x2 + (end.x2 - start.x2) * progress), AndroidUtilities.dp(start.y2 + (end.y2 - start.y2) * progress), - AndroidUtilities.dp(start.x + (end.x - start.x) * progress), AndroidUtilities.dp(start.y + (end.y - start.y) * progress)); - } else { - path.cubicTo(AndroidUtilities.dp(end.x1), AndroidUtilities.dp(end.y1), AndroidUtilities.dp(end.x2), AndroidUtilities.dp(end.y2), AndroidUtilities.dp(end.x), AndroidUtilities.dp(end.y)); + if (endCommand instanceof MoveTo) { + MoveTo end = (MoveTo) endCommand; + MoveTo start = (MoveTo) startCommand; + if (start != null) { + path.moveTo(AndroidUtilities.dpf2(start.x + (end.x - start.x) * progress), AndroidUtilities.dpf2(start.y + (end.y - start.y) * progress)); + } else { + path.moveTo(AndroidUtilities.dpf2(end.x), AndroidUtilities.dpf2(end.y)); + } + } else if (endCommand instanceof LineTo) { + LineTo end = (LineTo) endCommand; + LineTo start = (LineTo) startCommand; + if (start != null) { + path.lineTo(AndroidUtilities.dpf2(start.x + (end.x - start.x) * progress), AndroidUtilities.dpf2(start.y + (end.y - start.y) * progress)); + } else { + path.lineTo(AndroidUtilities.dpf2(end.x), AndroidUtilities.dpf2(end.y)); + } + } else if (endCommand instanceof CurveTo) { + CurveTo end = (CurveTo) endCommand; + CurveTo start = (CurveTo) startCommand; + if (start != null) { + path.cubicTo(AndroidUtilities.dpf2(start.x1 + (end.x1 - start.x1) * progress), AndroidUtilities.dpf2(start.y1 + (end.y1 - start.y1) * progress), + AndroidUtilities.dpf2(start.x2 + (end.x2 - start.x2) * progress), AndroidUtilities.dpf2(start.y2 + (end.y2 - start.y2) * progress), + AndroidUtilities.dpf2(start.x + (end.x - start.x) * progress), AndroidUtilities.dpf2(start.y + (end.y - start.y) * progress)); + } else { + path.cubicTo(AndroidUtilities.dpf2(end.x1), AndroidUtilities.dpf2(end.y1), AndroidUtilities.dpf2(end.x2), AndroidUtilities.dpf2(end.y2), AndroidUtilities.dpf2(end.x), AndroidUtilities.dpf2(end.y)); + } } } + path.close(); } - path.close(); canvas.drawPath(path, paint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java index 0f0e77d56..48a2baa2d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoPaintView.java @@ -454,6 +454,10 @@ public class PhotoPaintView extends FrameLayout implements EntityView.EntityView return toolsView; } + public FrameLayout getCurtainView() { + return curtainView; + } + public TextView getDoneTextView() { return doneTextView; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PinnedLineView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PinnedLineView.java new file mode 100644 index 000000000..fdcf1ce19 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PinnedLineView.java @@ -0,0 +1,283 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.view.View; + +import androidx.core.graphics.ColorUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; + +public class PinnedLineView extends View { + + int selectedPosition = -1; + int totalCount = 0; + + int animateToPosition; + float animateFromPosition; + int animateFromTotal; + int animateToTotal; + boolean animationInProgress; + + boolean replaceInProgress; + private float startOffsetFrom; + private float startOffsetTo; + private int lineHFrom; + private int lineHTo; + + RectF rectF = new RectF(); + float animationProgress; + ValueAnimator animator; + + Paint fadePaint; + Paint fadePaint2; + + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + Paint selectedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private int nextPosition = -1; + private int color; + + public PinnedLineView(Context context) { + super(context); + + paint.setStyle(Paint.Style.FILL); + paint.setStrokeCap(Paint.Cap.ROUND); + + selectedPaint.setStyle(Paint.Style.FILL); + selectedPaint.setStrokeCap(Paint.Cap.ROUND); + + fadePaint = new Paint(); + LinearGradient gradient = new LinearGradient(0, 0,0, AndroidUtilities.dp(6), new int[]{0xffffffff, 0}, new float[]{0f, 1f}, Shader.TileMode.CLAMP); + fadePaint.setShader(gradient); + fadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + + fadePaint2 = new Paint(); + gradient = new LinearGradient(0, 0,0, AndroidUtilities.dp(6), new int[]{0, 0xffffffff}, new float[]{0f, 1f}, Shader.TileMode.CLAMP); + fadePaint2.setShader(gradient); + fadePaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); + + updateColors(); + } + + public void updateColors() { + color = Theme.getColor(Theme.key_chat_topPanelLine); + paint.setColor(ColorUtils.setAlphaComponent(color, (int) ((Color.alpha(color) / 255f) * 112))); + selectedPaint.setColor(Theme.getColor(Theme.key_chat_topPanelLine)); + } + + private void selectPosition(int position) { + if (replaceInProgress) { + nextPosition = position; + return; + } + if (animationInProgress) { + if (animateToPosition == position) { + return; + } + if (animator != null) { + animator.cancel(); + } + animateFromPosition = animateFromPosition * (1f - animationProgress) + animateToPosition * animationProgress; + } else { + animateFromPosition = selectedPosition; + } + if (position != selectedPosition) { + animateToPosition = position; + animationInProgress = true; + animationProgress = 0; + invalidate(); + animator = ValueAnimator.ofFloat(0, 1f); + animator.addUpdateListener(valueAnimator -> { + animationProgress = (float) valueAnimator.getAnimatedValue(); + invalidate(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animationInProgress = false; + selectedPosition = animateToPosition; + invalidate(); + if (nextPosition >= 0) { + selectPosition(nextPosition); + nextPosition = -1; + } + } + }); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.setDuration(220); + animator.start(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (selectedPosition < 0 || totalCount == 0) { + return; + } + boolean drawFade = (replaceInProgress ? Math.max(animateFromTotal, animateToTotal) : totalCount) > 3; + if (drawFade) { + canvas.saveLayerAlpha(0, 0, getMeasuredWidth(), getMeasuredHeight(), 255, Canvas.ALL_SAVE_FLAG); + } + int viewPadding = AndroidUtilities.dp(8); + float lineH; + if (replaceInProgress) { + lineH = lineHFrom * (1f - animationProgress) + lineHTo * animationProgress; + } else { + if (totalCount == 0) { + return; + } + lineH = (getMeasuredHeight() - viewPadding * 2) / (float) (Math.min(totalCount, 3)); + } + if (lineH == 0) { + return; + } + float linePadding = AndroidUtilities.dpf2(0.7f); + + float startOffset; + if (replaceInProgress) { + startOffset = startOffsetFrom * (1f - animationProgress) + startOffsetTo * animationProgress; + } else { + if (animationInProgress) { + float offset1 = (animateFromPosition - 1) * lineH; + float offset2 = (animateToPosition - 1) * lineH; + startOffset = offset1 * (1f - animationProgress) + offset2 * animationProgress; + } else { + startOffset = (selectedPosition - 1) * lineH; + } + + if (startOffset < 0) { + startOffset = 0; + } else if (viewPadding + (totalCount - 1) * lineH - startOffset < getMeasuredHeight() - viewPadding - lineH) { + startOffset = (viewPadding + (totalCount - 1) * lineH) - (getMeasuredHeight() - viewPadding - lineH); + } + } + + float r = getMeasuredWidth() / 2f; + + int start = Math.max(0, (int) ((viewPadding + startOffset) / lineH - 1)); + int end = Math.min(start + 6, replaceInProgress ? Math.max(animateFromTotal, animateToTotal) : totalCount); + for (int i = start; i < end; i++) { + float startY = viewPadding + i * lineH - startOffset; + if (startY + lineH < 0 || startY > getMeasuredHeight()) { + continue; + } + rectF.set(0, startY + linePadding, getMeasuredWidth(), startY + lineH - linePadding); + if (replaceInProgress && i >= animateToTotal) { + paint.setColor(ColorUtils.setAlphaComponent(color, (int) ((Color.alpha(color) / 255f) * 76 * (1f - animationProgress)))); + canvas.drawRoundRect(rectF, r, r, paint); + paint.setColor(ColorUtils.setAlphaComponent(color, (int) ((Color.alpha(color) / 255f) * 76))); + } else if (replaceInProgress && i >= animateFromTotal) { + paint.setColor(ColorUtils.setAlphaComponent(color, (int) ((Color.alpha(color) / 255f) * 76 * animationProgress))); + canvas.drawRoundRect(rectF, r, r, paint); + paint.setColor(ColorUtils.setAlphaComponent(color, (int) ((Color.alpha(color) / 255f) * 76))); + } else { + canvas.drawRoundRect(rectF, r, r, paint); + } + + } + + if (animationInProgress) { + float startY = viewPadding + (animateFromPosition * (1f - animationProgress) + animateToPosition * animationProgress) * lineH - startOffset; + rectF.set(0, startY + linePadding, getMeasuredWidth(), startY + lineH - linePadding); + canvas.drawRoundRect(rectF, r, r, selectedPaint); + } else { + float startY = viewPadding + selectedPosition * lineH - startOffset; + rectF.set(0, startY + linePadding, getMeasuredWidth(), startY + lineH - linePadding); + canvas.drawRoundRect(rectF, r, r, selectedPaint); + } + + if (drawFade) { + canvas.drawRect(0, 0, getMeasuredWidth(), AndroidUtilities.dp(6), fadePaint); + canvas.drawRect(0, getMeasuredHeight() - AndroidUtilities.dp(6), getMeasuredWidth(), getMeasuredHeight(), fadePaint); + + canvas.translate(0, getMeasuredHeight() - AndroidUtilities.dp(6)); + canvas.drawRect(0, 0, getMeasuredWidth(), AndroidUtilities.dp(6), fadePaint2); + } + } + + public void set(int position, int totalCount, boolean animated) { + if (selectedPosition < 0 || totalCount == 0 || this.totalCount == 0) { + animated = false; + } + if (!animated) { + if (animator != null) { + animator.cancel(); + } + this.selectedPosition = position; + this.totalCount = totalCount; + invalidate(); + } else { + if (this.totalCount != totalCount || Math.abs(selectedPosition - position) > 2) { + if (animator != null) { + animator.cancel(); + } + int viewPadding = AndroidUtilities.dp(8); + lineHFrom = (getMeasuredHeight() - viewPadding * 2) / (Math.min(this.totalCount, 3)); + lineHTo = (getMeasuredHeight() - viewPadding * 2) / (Math.min(totalCount, 3)); + + startOffsetFrom = (selectedPosition - 1) * lineHFrom; + if (startOffsetFrom < 0) { + startOffsetFrom = 0; + } else if (viewPadding + (this.totalCount - 1) * lineHFrom - startOffsetFrom < getMeasuredHeight() - viewPadding - lineHFrom) { + startOffsetFrom = (viewPadding + (this.totalCount - 1) * lineHFrom) - (getMeasuredHeight() - viewPadding - lineHFrom); + } + + startOffsetTo = (position - 1) * lineHTo; + if (startOffsetTo < 0) { + startOffsetTo = 0; + } else if (viewPadding + (totalCount - 1) * lineHTo - startOffsetTo < getMeasuredHeight() - viewPadding - lineHTo) { + startOffsetTo = (viewPadding + (totalCount - 1) * lineHTo) - (getMeasuredHeight() - viewPadding - lineHTo); + } + animateFromPosition = selectedPosition; + animateToPosition = position; + + selectedPosition = position; + animateFromTotal = this.totalCount; + animateToTotal = totalCount; + this.totalCount = totalCount; + + replaceInProgress = true; + animationInProgress = true; + animationProgress = 0; + + invalidate(); + animator = ValueAnimator.ofFloat(0, 1f); + animator.addUpdateListener(valueAnimator -> { + animationProgress = (float) valueAnimator.getAnimatedValue(); + invalidate(); + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + replaceInProgress = false; + animationInProgress = false; + invalidate(); + if (nextPosition >= 0) { + selectPosition(nextPosition); + nextPosition = -1; + } + } + }); + animator.setInterpolator(CubicBezierInterpolator.DEFAULT); + animator.setDuration(220); + animator.start(); + } else { + selectPosition(position); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayPauseDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayPauseDrawable.java new file mode 100644 index 000000000..12ca076ca --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayPauseDrawable.java @@ -0,0 +1,115 @@ +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.animation.AnimationUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; + +public class PlayPauseDrawable extends Drawable { + + private final Paint paint; + private final int size; + + private boolean pause; + private float progress; + private long lastUpdateTime; + + public PlayPauseDrawable(int size) { + this.size = AndroidUtilities.dp(size); + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setColor(Color.WHITE); + } + + @Override + public void draw(@NonNull Canvas canvas) { + long newUpdateTime = AnimationUtils.currentAnimationTimeMillis(); + long dt = newUpdateTime - lastUpdateTime; + lastUpdateTime = newUpdateTime; + if (dt > 18) { + dt = 16; + } + if (pause && progress < 1f) { + progress += dt / 300f; + if (progress >= 1f) { + progress = 1f; + } else { + invalidateSelf(); + } + } else if (!pause && progress > 0f) { + progress -= dt / 300f; + if (progress <= 0f) { + progress = 0f; + } else { + invalidateSelf(); + } + } + final Rect bounds = getBounds(); + canvas.save(); + canvas.translate(bounds.centerX() + AndroidUtilities.dp(1) * (1.0f - progress), bounds.centerY()); + final float ms = 500.0f * progress; + final float rotation; + if (ms < 100) { + rotation = -5 * CubicBezierInterpolator.EASE_BOTH.getInterpolation(ms / 100.0f); + } else if (ms < 484) { + rotation = -5 + 95 * CubicBezierInterpolator.EASE_BOTH.getInterpolation((ms - 100) / 384); + } else { + rotation = 90; + } + canvas.scale(1.45f * size / AndroidUtilities.dp(28), 1.5f * size / AndroidUtilities.dp(28)); + canvas.rotate(rotation); + Theme.playPauseAnimator.draw(canvas, paint, ms); + canvas.scale(1.0f, -1.0f); + Theme.playPauseAnimator.draw(canvas, paint, ms); + canvas.restore(); + } + + public void setPause(boolean pause) { + setPause(pause, true); + } + + public void setPause(boolean pause, boolean animated) { + if (this.pause != pause) { + this.pause = pause; + if (!animated) { + progress = pause ? 1f : 0f; + } + this.lastUpdateTime = AnimationUtils.currentAnimationTimeMillis(); + invalidateSelf(); + } + } + + @Override + public void setAlpha(int i) { + paint.setAlpha(i); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + paint.setColorFilter(colorFilter); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return size; + } + + @Override + public int getIntrinsicHeight() { + return size; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayingGameDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayingGameDrawable.java index 28b912a0f..461697380 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayingGameDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayingGameDrawable.java @@ -29,11 +29,20 @@ public class PlayingGameDrawable extends StatusDrawable { private boolean started = false; private RectF rect = new RectF(); private float progress; + private final boolean isDialogScreen; + public PlayingGameDrawable(boolean isDialogScreen) { + this.isDialogScreen = isDialogScreen; + } public void setIsChat(boolean value) { isChat = value; } + @Override + public void setColor(int color) { + + } + private void update() { long newTime = System.currentTimeMillis(); long dt = newTime - lastUpdateTime; @@ -73,7 +82,7 @@ public class PlayingGameDrawable extends StatusDrawable { //y = AndroidUtilities.dp(9.3f) + getBounds().top; } - paint.setColor(Theme.getColor(Theme.key_chat_status)); + paint.setColor(Theme.getColor(isDialogScreen ? Theme.key_chats_actionMessage : Theme.key_chat_status)); rect.set(0, y, size, y + size); int rad; if (progress < 0.5f) { @@ -98,7 +107,7 @@ public class PlayingGameDrawable extends StatusDrawable { } paint.setAlpha(255); canvas.drawArc(rect, rad, 360 - rad * 2, true, paint); - paint.setColor(Theme.getColor(Theme.key_actionBarDefault)); + paint.setColor(Theme.getColor(isDialogScreen ? Theme.key_windowBackgroundWhite : Theme.key_actionBarDefault)); canvas.drawCircle(AndroidUtilities.dp(4), y + size / 2 - AndroidUtilities.dp(2), AndroidUtilities.dp(1), paint); checkUpdate(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ProximitySheet.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProximitySheet.java new file mode 100644 index 000000000..537756d79 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ProximitySheet.java @@ -0,0 +1,652 @@ +package org.telegram.ui.Components; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.content.Context; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.widget.Button; +import android.widget.FrameLayout; +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.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; + +import java.util.Locale; + +public class ProximitySheet extends FrameLayout { + + private VelocityTracker velocityTracker = null; + private int startedTrackingX; + private int startedTrackingY; + private int startedTrackingPointerId = -1; + private boolean maybeStartTracking = false; + private boolean startedTracking = false; + private AnimatorSet currentAnimation = null; + private android.graphics.Rect rect = new Rect(); + private Paint backgroundPaint = new Paint(); + + private boolean dismissed; + + private AnimatorSet currentSheetAnimation; + private int currentSheetAnimationType; + + private ViewGroup containerView; + + private boolean useHardwareLayer = true; + + private int backgroundPaddingTop; + private int backgroundPaddingLeft; + + private int touchSlop; + private boolean useFastDismiss; + private Interpolator openInterpolator = CubicBezierInterpolator.EASE_OUT_QUINT; + + private NumberPicker kmPicker; + private NumberPicker mPicker; + private onRadiusPickerChange onRadiusChange; + private TextView buttonTextView; + private TextView infoTextView; + private boolean radiusSet; + private TLRPC.User currentUser; + private int totalWidth; + private boolean useImperialSystem; + + private LinearLayout customView; + + private Runnable onDismissCallback; + + public interface onRadiusPickerChange { + boolean run(boolean move, int param); + } + + public ProximitySheet(Context context, TLRPC.User user, onRadiusPickerChange onRadius, onRadiusPickerChange onFinish, Runnable onDismiss) { + super(context); + setWillNotDraw(false); + onDismissCallback = onDismiss; + + ViewConfiguration vc = ViewConfiguration.get(context); + touchSlop = vc.getScaledTouchSlop(); + + Rect padding = new Rect(); + Drawable shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow_round).mutate(); + shadowDrawable.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogBackground), PorterDuff.Mode.MULTIPLY)); + shadowDrawable.getPadding(padding); + backgroundPaddingLeft = padding.left; + + containerView = new FrameLayout(getContext()) { + @Override + public boolean hasOverlappingRendering() { + return false; + } + }; + containerView.setBackgroundDrawable(shadowDrawable); + containerView.setPadding(backgroundPaddingLeft, AndroidUtilities.dp(8) + padding.top - 1, backgroundPaddingLeft, 0); + + containerView.setVisibility(View.INVISIBLE); + addView(containerView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + useImperialSystem = LocaleController.getUseImperialSystemType(); + currentUser = user; + + onRadiusChange = onRadius; + + kmPicker = new NumberPicker(context); + kmPicker.setTextOffset(AndroidUtilities.dp(10)); + kmPicker.setItemCount(5); + mPicker = new NumberPicker(context); + mPicker.setItemCount(5); + mPicker.setTextOffset(-AndroidUtilities.dp(10)); + + customView = new LinearLayout(context) { + + boolean ignoreLayout = false; + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + ignoreLayout = true; + int count; + if (AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y) { + count = 3; + } else { + count = 5; + } + kmPicker.setItemCount(count); + mPicker.setItemCount(count); + kmPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + mPicker.getLayoutParams().height = AndroidUtilities.dp(54) * count; + ignoreLayout = false; + int prewWidth = 0; + totalWidth = MeasureSpec.getSize(widthMeasureSpec); + if (prewWidth != totalWidth) { + updateText(false, false); + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + customView.setOrientation(LinearLayout.VERTICAL); + + FrameLayout titleLayout = new FrameLayout(context); + customView.addView(titleLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 22, 0, 0, 4)); + + TextView titleView = new TextView(context); + titleView.setText(LocaleController.getString("LocationNotifiation", R.string.LocationNotifiation)); + titleView.setTextColor(Theme.getColor(Theme.key_dialogTextBlack)); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleLayout.addView(titleView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 12, 0, 0)); + titleView.setOnTouchListener((v, event) -> true); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.setWeightSum(1.0f); + customView.addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + long currentTime = System.currentTimeMillis(); + + FrameLayout buttonContainer = new FrameLayout(context); + + infoTextView = new TextView(context); + + buttonTextView = new TextView(context) { + @Override + public CharSequence getAccessibilityClassName() { + return Button.class.getName(); + } + }; + + linearLayout.addView(kmPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + kmPicker.setFormatter(value -> { + if (useImperialSystem) { + return LocaleController.formatString("MilesShort", R.string.MilesShort, value); + } else { + return LocaleController.formatString("KMetersShort", R.string.KMetersShort, value); + } + }); + kmPicker.setMinValue(0); + kmPicker.setMaxValue(10); + kmPicker.setWrapSelectorWheel(false); + kmPicker.setTextOffset(AndroidUtilities.dp(20)); + final NumberPicker.OnValueChangeListener onValueChangeListener = (picker, oldVal, newVal) -> { + try { + performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); + } catch (Exception ignore) { + + } + updateText(true, true); + }; + kmPicker.setOnValueChangedListener(onValueChangeListener); + + mPicker.setMinValue(0); + mPicker.setMaxValue(10); + mPicker.setWrapSelectorWheel(false); + mPicker.setTextOffset(-AndroidUtilities.dp(20)); + linearLayout.addView(mPicker, LayoutHelper.createLinear(0, 54 * 5, 0.5f)); + mPicker.setFormatter(value -> { + if (useImperialSystem) { + if (value == 1) { + return LocaleController.formatString("FootsShort", R.string.FootsShort, 250); + } else { + if (value > 1) { + value--; + } + return String.format(Locale.US, ".%d", value); + } + } else { + if (value == 1) { + return LocaleController.formatString("MetersShort", R.string.MetersShort, 50); + } else { + if (value > 1) { + value--; + } + return LocaleController.formatString("MetersShort", R.string.MetersShort, value * 100); + } + } + }); + mPicker.setOnValueChangedListener(onValueChangeListener); + + kmPicker.setValue(0); + mPicker.setValue(6); + + customView.addView(buttonContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM, 16, 15, 16, 16)); + + buttonTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + buttonTextView.setGravity(Gravity.CENTER); + buttonTextView.setTextColor(Theme.getColor(Theme.key_featuredStickers_buttonText)); + buttonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + buttonTextView.setMaxLines(2); + buttonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + buttonTextView.setBackgroundDrawable(Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(4), Theme.getColor(Theme.key_featuredStickers_addButton), Theme.getColor(Theme.key_featuredStickers_addButtonPressed))); + buttonContainer.addView(buttonTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + buttonTextView.setOnClickListener(v -> { + if (buttonTextView.getTag() != null) { + return; + } + float value = getValue(); + if (onFinish.run(true, (int) Math.max(1, value))) { + dismiss(); + } + }); + + infoTextView.setPadding(AndroidUtilities.dp(34), 0, AndroidUtilities.dp(34), 0); + infoTextView.setGravity(Gravity.CENTER); + infoTextView.setTextColor(Theme.getColor(Theme.key_dialogTextGray2)); + infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + infoTextView.setAlpha(0.0f); + infoTextView.setScaleX(0.5f); + infoTextView.setScaleY(0.5f); + buttonContainer.addView(infoTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48)); + + containerView.addView(customView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); + } + + public View getCustomView() { + return customView; + } + + public float getValue() { + float value = kmPicker.getValue() * 1000; + int second = mPicker.getValue(); + if (useImperialSystem) { + if (second == 1) { + value += 47.349f; + } else { + if (second > 1) { + second--; + } + value += second * 100; + } + } else { + if (second == 1) { + value += 50; + } else { + if (second > 1) { + second--; + } + value += second * 100; + } + } + if (useImperialSystem) { + value *= 1.60934f; + } + return value; + } + + public boolean getRadiusSet() { + return radiusSet; + } + + public void setRadiusSet() { + radiusSet = true; + } + + public void updateText(boolean move, boolean animated) { + float value = getValue(); + String distance = LocaleController.formatDistance(value, 2, useImperialSystem); + if (onRadiusChange.run(move, (int) value) || currentUser == null) { + if (currentUser == null) { + buttonTextView.setText(LocaleController.formatString("LocationNotifiationButtonGroup", R.string.LocationNotifiationButtonGroup, distance)); + } else { + String format = LocaleController.getString("LocationNotifiationButtonUser", R.string.LocationNotifiationButtonUser); + int width = (int) Math.ceil(buttonTextView.getPaint().measureText(format)); + int restWidth = (int) ((totalWidth - AndroidUtilities.dp(32 + 62)) * 1.5f - width); + CharSequence name = TextUtils.ellipsize(UserObject.getFirstName(currentUser), buttonTextView.getPaint(), Math.max(AndroidUtilities.dp(10), restWidth), TextUtils.TruncateAt.END); + buttonTextView.setText(LocaleController.formatString("LocationNotifiationButtonUser", R.string.LocationNotifiationButtonUser, name, distance)); + } + if (buttonTextView.getTag() != null) { + buttonTextView.setTag(null); + buttonTextView.animate().setDuration(180).alpha(1.0f).scaleX(1.0f).scaleY(1.0f).start(); + infoTextView.animate().setDuration(180).alpha(0.0f).scaleX(0.5f).scaleY(0.5f).start(); + } + } else { + infoTextView.setText(LocaleController.formatString("LocationNotifiationCloser", R.string.LocationNotifiationCloser, distance)); + if (buttonTextView.getTag() == null) { + buttonTextView.setTag(1); + buttonTextView.animate().setDuration(180).alpha(0.0f).scaleX(0.5f).scaleY(0.5f).start(); + infoTextView.animate().setDuration(180).alpha(1.0f).scaleX(1.0f).scaleY(1.0f).start(); + } + } + } + + private void checkDismiss(float velX, float velY) { + float translationY = containerView.getTranslationY(); + boolean backAnimation = translationY < AndroidUtilities.getPixelsInCM(0.8f, false) && (velY < 3500 || Math.abs(velY) < Math.abs(velX)) || velY < 0 && Math.abs(velY) >= 3500; + if (!backAnimation) { + useFastDismiss = true; + dismiss(); + } else { + currentAnimation = new AnimatorSet(); + currentAnimation.playTogether(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, 0)); + currentAnimation.setDuration((int) (150 * (Math.max(0, translationY) / AndroidUtilities.getPixelsInCM(0.8f, false)))); + currentAnimation.setInterpolator(CubicBezierInterpolator.EASE_OUT); + currentAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (currentAnimation != null && currentAnimation.equals(animation)) { + currentAnimation = null; + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + } + }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + currentAnimation.start(); + } + } + + private void cancelCurrentAnimation() { + if (currentAnimation != null) { + currentAnimation.cancel(); + currentAnimation = null; + } + } + + boolean processTouchEvent(MotionEvent ev, boolean intercept) { + if (dismissed) { + return false; + } + if (ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && (!startedTracking && !maybeStartTracking && ev.getPointerCount() == 1)) { + startedTrackingX = (int) ev.getX(); + startedTrackingY = (int) ev.getY(); + if (startedTrackingY < containerView.getTop() || startedTrackingX < containerView.getLeft() || startedTrackingX > containerView.getRight()) { + requestDisallowInterceptTouchEvent(true); + dismiss(); + return true; + } + startedTrackingPointerId = ev.getPointerId(0); + maybeStartTracking = true; + cancelCurrentAnimation(); + if (velocityTracker != null) { + velocityTracker.clear(); + } + } else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) { + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + float dx = Math.abs((int) (ev.getX() - startedTrackingX)); + float dy = (int) ev.getY() - startedTrackingY; + velocityTracker.addMovement(ev); + if (maybeStartTracking && !startedTracking && (dy > 0 && dy / 3.0f > Math.abs(dx) && Math.abs(dy) >= touchSlop)) { + startedTrackingY = (int) ev.getY(); + maybeStartTracking = false; + startedTracking = true; + requestDisallowInterceptTouchEvent(true); + } else if (startedTracking) { + float translationY = containerView.getTranslationY(); + translationY += dy; + if (translationY < 0) { + translationY = 0; + } + containerView.setTranslationY(translationY); + startedTrackingY = (int) ev.getY(); + } + } else if (ev == null || ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) { + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + velocityTracker.computeCurrentVelocity(1000); + float translationY = containerView.getTranslationY(); + if (startedTracking || translationY != 0) { + checkDismiss(velocityTracker.getXVelocity(), velocityTracker.getYVelocity()); + startedTracking = false; + } else { + maybeStartTracking = false; + startedTracking = false; + } + if (velocityTracker != null) { + velocityTracker.recycle(); + velocityTracker = null; + } + startedTrackingPointerId = -1; + } + return !intercept && maybeStartTracking || startedTracking; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + return dismissed || processTouchEvent(ev, false); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + View rootView = getRootView(); + getWindowVisibleDisplayFrame(rect); + + setMeasuredDimension(width, height); + + containerView.measure(MeasureSpec.makeMeasureSpec(width + backgroundPaddingLeft * 2, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child.getVisibility() == GONE || child == containerView) { + continue; + } + measureChildWithMargins(child, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 0, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), 0); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int t = (bottom - top) - containerView.getMeasuredHeight(); + int l = ((right - left) - containerView.getMeasuredWidth()) / 2; + containerView.layout(l, t, l + containerView.getMeasuredWidth(), t + containerView.getMeasuredHeight()); + + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == GONE || child == containerView) { + continue; + } + + final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams(); + + final int width = child.getMeasuredWidth(); + final int height = child.getMeasuredHeight(); + + int childLeft; + int childTop; + + int gravity = lp.gravity; + if (gravity == -1) { + gravity = Gravity.TOP | Gravity.LEFT; + } + + final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + childLeft = (right - left - width) / 2 + lp.leftMargin - lp.rightMargin; + break; + case Gravity.RIGHT: + childLeft = right - width - lp.rightMargin; + break; + case Gravity.LEFT: + default: + childLeft = lp.leftMargin; + } + + switch (verticalGravity) { + case Gravity.CENTER_VERTICAL: + childTop = (bottom - top - height) / 2 + lp.topMargin - lp.bottomMargin; + break; + case Gravity.BOTTOM: + childTop = (bottom - top) - height - lp.bottomMargin; + break; + default: + childTop = lp.topMargin; + } + child.layout(childLeft, childTop, childLeft + width, childTop + height); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return dismissed || processTouchEvent(event, true); + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + if (maybeStartTracking && !startedTracking) { + onTouchEvent(null); + } + super.requestDisallowInterceptTouchEvent(disallowIntercept); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + public void show() { + dismissed = false; + cancelSheetAnimation(); + containerView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x + backgroundPaddingLeft * 2, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); + startOpenAnimation(); + updateText(true, false); + } + + private void cancelSheetAnimation() { + if (currentSheetAnimation != null) { + currentSheetAnimation.cancel(); + currentSheetAnimation = null; + currentSheetAnimationType = 0; + } + } + + private void startOpenAnimation() { + if (dismissed) { + return; + } + containerView.setVisibility(View.VISIBLE); + + if (Build.VERSION.SDK_INT >= 20 && useHardwareLayer) { + setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + containerView.setTranslationY(containerView.getMeasuredHeight()); + currentSheetAnimationType = 1; + currentSheetAnimation = new AnimatorSet(); + currentSheetAnimation.playTogether(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, 0)); + currentSheetAnimation.setDuration(400); + currentSheetAnimation.setStartDelay(20); + currentSheetAnimation.setInterpolator(openInterpolator); + currentSheetAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { + currentSheetAnimation = null; + currentSheetAnimationType = 0; + if (useHardwareLayer) { + setLayerType(View.LAYER_TYPE_NONE, null); + } + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + } + + @Override + public void onAnimationCancel(Animator animation) { + if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { + currentSheetAnimation = null; + currentSheetAnimationType = 0; + } + } + }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + currentSheetAnimation.start(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + if (dismissed) { + return true; + } + return super.dispatchTouchEvent(ev); + } + + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + cancelSheetAnimation(); + + currentSheetAnimationType = 2; + currentSheetAnimation = new AnimatorSet(); + currentSheetAnimation.playTogether(ObjectAnimator.ofFloat(containerView, View.TRANSLATION_Y, containerView.getMeasuredHeight() + AndroidUtilities.dp(10))); + if (useFastDismiss) { + int height = containerView.getMeasuredHeight(); + currentSheetAnimation.setDuration(Math.max(60, (int) (250 * (height - containerView.getTranslationY()) / (float) height))); + useFastDismiss = false; + } else { + currentSheetAnimation.setDuration(250); + } + currentSheetAnimation.setInterpolator(CubicBezierInterpolator.DEFAULT); + currentSheetAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { + currentSheetAnimation = null; + currentSheetAnimationType = 0; + AndroidUtilities.runOnUIThread(() -> { + try { + dismissInternal(); + } catch (Exception e) { + FileLog.e(e); + } + }); + } + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.startAllHeavyOperations, 512); + } + + @Override + public void onAnimationCancel(Animator animation) { + if (currentSheetAnimation != null && currentSheetAnimation.equals(animation)) { + currentSheetAnimation = null; + currentSheetAnimationType = 0; + } + } + }); + NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.stopAllHeavyOperations, 512); + currentSheetAnimation.start(); + } + + private void dismissInternal() { + if (getParent() instanceof ViewGroup) { + ViewGroup parent = (ViewGroup) getParent(); + parent.removeView(this); + } + onDismissCallback.run(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java index 7b40ecfbd..d579717a0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieDrawable.java @@ -45,19 +45,19 @@ import tw.nekomimi.nekogram.NekoConfig; public class RLottieDrawable extends BitmapDrawable implements Animatable { public static native long create(String src, int w, int h, int[] params, boolean precache, int[] colorReplacement, boolean limitFps); - private static native long createWithJson(String json, String name, int[] params, int[] colorReplacement); + protected static native long createWithJson(String json, String name, int[] params, int[] colorReplacement); public static native void destroy(long ptr); private static native void setLayerColor(long ptr, String layer, int color); private static native void replaceColors(long ptr, int[] colorReplacement); - public static native int getFrame(long ptr, int frame, Bitmap bitmap, int w, int h, int stride); + public static native int getFrame(long ptr, int frame, Bitmap bitmap, int w, int h, int stride, boolean clear); private static native void createCache(long ptr, int w, int h); - private int width; - private int height; - private final int[] metaData = new int[3]; - private int timeBetweenFrames; - private int customEndFrame = -1; - private boolean playInDirectionOfCustomEndFrame; + protected int width; + protected int height; + protected final int[] metaData = new int[3]; + protected int timeBetweenFrames; + protected int customEndFrame = -1; + protected boolean playInDirectionOfCustomEndFrame; private int[] newReplaceColors; private int[] pendingReplaceColors; private HashMap newColorUpdates = new HashMap<>(); @@ -65,51 +65,51 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { private HashMap vibrationPattern; private WeakReference frameReadyCallback; - private WeakReference onFinishCallback; + protected WeakReference onFinishCallback; private int finishFrame; private View currentParentView; - private int isDice; - private int diceSwitchFramesCount = -1; + protected int isDice; + protected int diceSwitchFramesCount = -1; - private int autoRepeat = 1; - private int autoRepeatPlayCount; + protected int autoRepeat = 1; + protected int autoRepeatPlayCount; private long lastFrameTime; - private volatile boolean nextFrameIsLast; + protected volatile boolean nextFrameIsLast; - private Runnable cacheGenerateTask; - private Runnable loadFrameTask; - private volatile Bitmap renderingBitmap; - private volatile Bitmap nextRenderingBitmap; - private volatile Bitmap backgroundBitmap; - private boolean waitingForNextTask; + protected Runnable cacheGenerateTask; + protected Runnable loadFrameTask; + protected volatile Bitmap renderingBitmap; + protected volatile Bitmap nextRenderingBitmap; + protected volatile Bitmap backgroundBitmap; + protected boolean waitingForNextTask; - private CountDownLatch frameWaitSync; + protected CountDownLatch frameWaitSync; - private boolean destroyWhenDone; + protected boolean destroyWhenDone; private boolean decodeSingleFrame; private boolean singleFrameDecoded; private boolean forceFrameRedraw; private boolean applyingLayerColors; - private int currentFrame; + protected int currentFrame; private boolean shouldLimitFps; private float scaleX = 1.0f; private float scaleY = 1.0f; private boolean applyTransformation; private final Rect dstRect = new Rect(); - private static final Handler uiHandler = new Handler(Looper.getMainLooper()); - private volatile boolean isRunning; - private volatile boolean isRecycled; - private volatile long nativePtr; - private volatile long secondNativePtr; - private boolean loadingInBackground; - private boolean secondLoadingInBackground; - private boolean destroyAfterLoading; - private int secondFramesCount; - private volatile boolean setLastFrame; + protected static final Handler uiHandler = new Handler(Looper.getMainLooper()); + protected volatile boolean isRunning; + protected volatile boolean isRecycled; + protected volatile long nativePtr; + protected volatile long secondNativePtr; + protected boolean loadingInBackground; + protected boolean secondLoadingInBackground; + protected boolean destroyAfterLoading; + protected int secondFramesCount; + protected volatile boolean setLastFrame; private boolean invalidateOnProgressSet; private boolean isInvalid; @@ -122,7 +122,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { private static DispatchQueuePool loadFrameRunnableQueue = new DispatchQueuePool(4); private static ThreadPoolExecutor lottieCacheGenerateQueue; - private Runnable uiRunnableNoFrame = new Runnable() { + protected Runnable uiRunnableNoFrame = new Runnable() { @Override public void run() { loadFrameTask = null; @@ -138,7 +138,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } }; - private Runnable uiRunnable = new Runnable() { + protected Runnable uiRunnable = new Runnable() { @Override public void run() { singleFrameDecoded = true; @@ -173,7 +173,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } }; - private void checkRunningTasks() { + protected void checkRunningTasks() { if (cacheGenerateTask != null) { if (lottieCacheGenerateQueue.remove(cacheGenerateTask)) { cacheGenerateTask = null; @@ -185,7 +185,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } } - private void decodeFrameFinishedInternal() { + protected void decodeFrameFinishedInternal() { if (destroyWhenDone) { checkRunningTasks(); if (loadFrameTask == null && cacheGenerateTask == null && nativePtr != 0) { @@ -208,7 +208,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { scheduleNextGetFrame(); } - private void recycleResources() { + protected void recycleResources() { if (renderingBitmap != null) { renderingBitmap.recycle(); renderingBitmap = null; @@ -228,7 +228,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } } - private Runnable loadFrameRunnable = new Runnable() { + protected Runnable loadFrameRunnable = new Runnable() { @Override public void run() { if (isRecycled) { @@ -275,7 +275,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } else { ptrToUse = nativePtr; } - int result = getFrame(ptrToUse, currentFrame, backgroundBitmap, width, height, backgroundBitmap.getRowBytes()); + int result = getFrame(ptrToUse, currentFrame, backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), true); if (result == -1) { uiHandler.post(uiRunnableNoFrame); if (frameWaitSync != null) { @@ -426,10 +426,8 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { return; } timeBetweenFrames = Math.max(16, (int) (1000.0f / metaData[1])); - if (isRunning) { - scheduleNextGetFrame(); - invalidateInternal(); - } + scheduleNextGetFrame(); + invalidateInternal(); }); }); @@ -473,10 +471,8 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } secondFramesCount = metaData2[0]; timeBetweenFrames = Math.max(16, (int) (1000.0f / metaData2[1])); - if (isRunning) { - scheduleNextGetFrame(); - invalidateInternal(); - } + scheduleNextGetFrame(); + invalidateInternal(); }); }); return true; @@ -498,7 +494,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } } - private String readRes(File path, int rawRes) { + public static String readRes(File path, int rawRes) { int totalRead = 0; byte[] readBuffer = readBufferLocal.get(); if (readBuffer == null) { @@ -594,7 +590,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } } - private boolean hasParentView() { + protected boolean hasParentView() { if (getCallback() != null) { return true; } @@ -611,7 +607,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { return false; } - private void invalidateInternal() { + protected void invalidateInternal() { for (int a = 0, N = parentViews.size(); a < N; a++) { View view = parentViews.get(a).get(); if (view != null) { @@ -752,7 +748,7 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { invalidateInternal(); } - private boolean scheduleNextGetFrame() { + protected boolean scheduleNextGetFrame() { if (loadFrameTask != null || nextRenderingBitmap != null || nativePtr == 0 || loadingInBackground || destroyWhenDone || !isRunning && (!decodeSingleFrame || decodeSingleFrame && singleFrameDecoded)) { return false; } @@ -768,6 +764,10 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { return true; } + public boolean isHeavyDrawable() { + return isDice == 0; + } + @Override public void stop() { isRunning = false; @@ -928,6 +928,27 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { if (nativePtr == 0 || destroyWhenDone) { return; } + updateCurrentFrame(); + + if (!isInvalid && renderingBitmap != null) { + if (applyTransformation) { + dstRect.set(getBounds()); + scaleX = (float) dstRect.width() / width; + scaleY = (float) dstRect.height() / height; + applyTransformation = false; + } + canvas.save(); + canvas.translate(dstRect.left, dstRect.top); + canvas.scale(scaleX, scaleY); + canvas.drawBitmap(renderingBitmap, 0, 0, getPaint()); + if (isRunning) { + invalidateInternal(); + } + canvas.restore(); + } + } + + public void updateCurrentFrame() { long now = SystemClock.elapsedRealtime(); long timeDiff = Math.abs(now - lastFrameTime); int timeCheck; @@ -951,23 +972,6 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable { } else if ((forceFrameRedraw || decodeSingleFrame && timeDiff >= timeCheck) && nextRenderingBitmap != null) { setCurrentFrame(now, timeDiff, timeCheck, true); } - - if (!isInvalid && renderingBitmap != null) { - if (applyTransformation) { - dstRect.set(getBounds()); - scaleX = (float) dstRect.width() / width; - scaleY = (float) dstRect.height() / height; - applyTransformation = false; - } - canvas.save(); - canvas.translate(dstRect.left, dstRect.top); - canvas.scale(scaleX, scaleY); - canvas.drawBitmap(renderingBitmap, 0, 0, getPaint()); - if (isRunning) { - invalidateInternal(); - } - canvas.restore(); - } } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java index 52871e831..102fa0064 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RLottieImageView.java @@ -20,6 +20,10 @@ public class RLottieImageView extends ImageView { super(context); } + public void clearLayerColors() { + layerColors.clear(); + } + public void setLayerColor(String layer, int color) { if (layerColors == null) { layerColors = new HashMap<>(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java index d8e43a972..128da960d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress2.java @@ -39,11 +39,15 @@ public class RadialProgress2 { private Paint circleMiniPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private MediaActionDrawable mediaActionDrawable; private MediaActionDrawable miniMediaActionDrawable; + private float miniIconScale = 1.0f; private int circleColor; private int circlePressedColor; private int iconColor; private int iconPressedColor; private String circleColorKey; + private String circleCrossfadeColorKey; + private float circleCrossfadeColorProgress; + private float circleCheckProgress = 1.0f; private String circlePressedColorKey; private String iconColorKey; private String iconPressedColorKey; @@ -134,6 +138,16 @@ public class RadialProgress2 { iconPressedColorKey = iconPressed; } + public void setCircleCrossfadeColor(String color, float progress, float checkProgress) { + circleCrossfadeColorKey = color; + circleCrossfadeColorProgress = progress; + circleCheckProgress = checkProgress; + miniIconScale = 1.0f; + if (color != null) { + initMiniIcons(); + } + } + public void setDrawBackground(boolean value) { drawBackground = value; } @@ -191,6 +205,10 @@ public class RadialProgress2 { } } + public void setMiniIconScale(float scale) { + miniIconScale = scale; + } + public void setMiniIcon(int icon, boolean ifSame, boolean animated) { if (icon != MediaActionDrawable.ICON_DOWNLOAD && icon != MediaActionDrawable.ICON_CANCEL && icon != MediaActionDrawable.ICON_NONE) { return; @@ -268,7 +286,7 @@ public class RadialProgress2 { wholeAlpha = currentIcon != MediaActionDrawable.ICON_NONE ? 1.0f : 1.0f - mediaActionDrawable.getTransitionProgress(); } - if (isPressedMini) { + if (isPressedMini && circleCrossfadeColorKey == null) { if (iconPressedColorKey != null) { miniMediaActionDrawable.setColor(Theme.getColor(iconPressedColorKey)); } else { @@ -286,7 +304,11 @@ public class RadialProgress2 { miniMediaActionDrawable.setColor(iconColor); } if (circleColorKey != null) { - circleMiniPaint.setColor(Theme.getColor(circleColorKey)); + if (circleCrossfadeColorKey != null) { + circleMiniPaint.setColor(AndroidUtilities.getOffsetColor(Theme.getColor(circleColorKey), Theme.getColor(circleCrossfadeColorKey), circleCrossfadeColorProgress, circleCheckProgress)); + } else { + circleMiniPaint.setColor(Theme.getColor(circleColorKey)); + } } else { circleMiniPaint.setColor(circleColor); } @@ -320,7 +342,7 @@ public class RadialProgress2 { circlePaint.setColor(circleColor); } } - if (drawMiniIcon && miniDrawCanvas != null) { + if ((drawMiniIcon || circleCrossfadeColorKey != null) && miniDrawCanvas != null) { miniDrawBitmap.eraseColor(0); } @@ -332,7 +354,7 @@ public class RadialProgress2 { boolean drawCircle = true; int centerX; int centerY; - if (drawMiniIcon && miniDrawCanvas != null) { + if ((drawMiniIcon || circleCrossfadeColorKey != null) && miniDrawCanvas != null) { centerX = (int) Math.ceil(progressRect.width() / 2); centerY = (int) Math.ceil(progressRect.height() / 2); } else { @@ -364,8 +386,14 @@ public class RadialProgress2 { overlayImageView.setImageCoords(centerX - circleRadius, centerY - circleRadius, circleRadius * 2, circleRadius * 2); } + int restore = Integer.MIN_VALUE; + if (miniDrawCanvas != null && circleCrossfadeColorKey != null && circleCheckProgress != 1.0f) { + restore = miniDrawCanvas.save(); + float scale = 1.0f - 0.1f * (1.0f - circleCheckProgress); + miniDrawCanvas.scale(scale, scale, centerX, centerY); + } if (drawCircle && drawBackground) { - if (drawMiniIcon && miniDrawCanvas != null) { + if ((drawMiniIcon || circleCrossfadeColorKey != null) && miniDrawCanvas != null) { miniDrawCanvas.drawCircle(centerX, centerY, circleRadius, circlePaint); } else { if (currentIcon != MediaActionDrawable.ICON_NONE || wholeAlpha != 0) { @@ -380,7 +408,7 @@ public class RadialProgress2 { if (overlayImageView.hasBitmapImage()) { overlayImageView.setAlpha(wholeAlpha * overrideAlpha); - if (drawMiniIcon && miniDrawCanvas != null) { + if ((drawMiniIcon || circleCrossfadeColorKey != null) && miniDrawCanvas != null) { overlayImageView.draw(miniDrawCanvas); miniDrawCanvas.drawCircle(centerX, centerY, circleRadius, overlayPaint); } else { @@ -390,7 +418,7 @@ public class RadialProgress2 { } mediaActionDrawable.setBounds(centerX - circleRadius, centerY - circleRadius, centerX + circleRadius, centerY + circleRadius); mediaActionDrawable.setHasOverlayImage(overlayImageView.hasBitmapImage()); - if (drawMiniIcon) { + if ((drawMiniIcon || circleCrossfadeColorKey != null)) { if (miniDrawCanvas != null) { mediaActionDrawable.draw(miniDrawCanvas); } else { @@ -400,8 +428,11 @@ public class RadialProgress2 { mediaActionDrawable.setOverrideAlpha(overrideAlpha); mediaActionDrawable.draw(canvas); } + if (restore != Integer.MIN_VALUE && miniDrawCanvas != null) { + miniDrawCanvas.restoreToCount(restore); + } - if (drawMiniIcon) { + if ((drawMiniIcon || circleCrossfadeColorKey != null)) { int offset; int size; float cx; @@ -419,13 +450,18 @@ public class RadialProgress2 { } int halfSize = size / 2; - float alpha = miniMediaActionDrawable.getCurrentIcon() != MediaActionDrawable.ICON_NONE ? 1.0f : 1.0f - miniMediaActionDrawable.getTransitionProgress(); - if (alpha == 0.0f) { - drawMiniIcon = false; + float alpha; + if (drawMiniIcon) { + alpha = miniMediaActionDrawable.getCurrentIcon() != MediaActionDrawable.ICON_NONE ? 1.0f : 1.0f - miniMediaActionDrawable.getTransitionProgress(); + if (alpha == 0.0f) { + drawMiniIcon = false; + } + } else { + alpha = 1.0f; } if (miniDrawCanvas != null) { - miniDrawCanvas.drawCircle(AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(halfSize + 1) * alpha, Theme.checkboxSquare_eraserPaint); + miniDrawCanvas.drawCircle(AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(18 + size + offset), AndroidUtilities.dp(halfSize + 1) * alpha * miniIconScale, Theme.checkboxSquare_eraserPaint); } else { miniProgressBackgroundPaint.setColor(progressColor); canvas.drawCircle(cx, cy, AndroidUtilities.dp(12), miniProgressBackgroundPaint); @@ -435,9 +471,20 @@ public class RadialProgress2 { canvas.drawBitmap(miniDrawBitmap, (int) progressRect.left, (int) progressRect.top, null); } - canvas.drawCircle(cx, cy, AndroidUtilities.dp(halfSize) * alpha, circleMiniPaint); - miniMediaActionDrawable.setBounds((int) (cx - AndroidUtilities.dp(halfSize) * alpha), (int) (cy - AndroidUtilities.dp(halfSize) * alpha), (int) (cx + AndroidUtilities.dp(halfSize) * alpha), (int) (cy + AndroidUtilities.dp(halfSize) * alpha)); - miniMediaActionDrawable.draw(canvas); + restore = Integer.MIN_VALUE; + if (miniIconScale < 1.0f) { + restore = canvas.save(); + canvas.scale(miniIconScale, miniIconScale, cx, cy); + } + + canvas.drawCircle(cx, cy, AndroidUtilities.dp(halfSize) * alpha + AndroidUtilities.dp(1) * (1.0f - circleCheckProgress), circleMiniPaint); + if (drawMiniIcon) { + miniMediaActionDrawable.setBounds((int) (cx - AndroidUtilities.dp(halfSize) * alpha), (int) (cy - AndroidUtilities.dp(halfSize) * alpha), (int) (cx + AndroidUtilities.dp(halfSize) * alpha), (int) (cy + AndroidUtilities.dp(halfSize) * alpha)); + miniMediaActionDrawable.draw(canvas); + } + if (restore != Integer.MIN_VALUE) { + canvas.restoreToCount(restore); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java index d6ca6c812..ce747f96b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java @@ -10,6 +10,7 @@ package org.telegram.ui.Components; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Paint; import android.graphics.RectF; import org.telegram.messenger.AndroidUtilities; @@ -23,10 +24,28 @@ public class RecordStatusDrawable extends StatusDrawable { private RectF rect = new RectF(); private float progress; + Paint currentPaint; + + public RecordStatusDrawable(boolean createPaint) { + if (createPaint) { + currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + currentPaint.setStyle(Paint.Style.STROKE); + currentPaint.setStrokeCap(Paint.Cap.ROUND); + currentPaint.setStrokeWidth(AndroidUtilities.dp(2)); + } + } + public void setIsChat(boolean value) { isChat = value; } + @Override + public void setColor(int color) { + if (currentPaint != null) { + currentPaint.setColor(color); + } + } + private void update() { long newTime = System.currentTimeMillis(); long dt = newTime - lastUpdateTime; @@ -53,19 +72,20 @@ public class RecordStatusDrawable extends StatusDrawable { @Override public void draw(Canvas canvas) { + Paint paint = currentPaint == null ? Theme.chat_statusRecordPaint : currentPaint; canvas.save(); canvas.translate(0, getIntrinsicHeight() / 2 + AndroidUtilities.dp(isChat ? 1 : 2)); for (int a = 0; a < 4; a++) { if (a == 0) { - Theme.chat_statusRecordPaint.setAlpha((int) (255 * progress)); + paint.setAlpha((int) (255 * progress)); } else if (a == 3) { - Theme.chat_statusRecordPaint.setAlpha((int) (255 * (1.0f - progress))); + paint.setAlpha((int) (255 * (1.0f - progress))); } else { - Theme.chat_statusRecordPaint.setAlpha(255); + paint.setAlpha(255); } float side = AndroidUtilities.dp(4) * a + AndroidUtilities.dp(4) * progress; rect.set(-side, -side, side, side); - canvas.drawArc(rect, -15, 30, false, Theme.chat_statusRecordPaint); + canvas.drawArc(rect, -15, 30, false, paint); } canvas.restore(); if (started) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerAnimationScrollHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerAnimationScrollHelper.java index 6b8a15e5e..b504426f8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerAnimationScrollHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerAnimationScrollHelper.java @@ -9,8 +9,9 @@ import android.view.View; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BuildVars; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.SharedConfig; import org.telegram.ui.Cells.ChatMessageCell; import java.util.ArrayList; @@ -58,7 +59,7 @@ public class RecyclerAnimationScrollHelper { } int n = recyclerView.getChildCount(); - if (n == 0) { + if (n == 0 || !MessagesController.getGlobalMainSettings().getBoolean("view_animations", true)) { layoutManager.scrollToPositionWithOffset(position, offset, bottom); return; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java index c082041c1..768b8dc9b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecyclerListView.java @@ -1890,4 +1890,12 @@ public class RecyclerListView extends RecyclerView { return false; } } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + if (fastScroll != null) { + fastScroll.setTranslationY(translationY); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RoundStatusDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RoundStatusDrawable.java index 84017d7c2..812472e56 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RoundStatusDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RoundStatusDrawable.java @@ -10,6 +10,7 @@ package org.telegram.ui.Components; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Paint; import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.ActionBar.Theme; @@ -22,6 +23,21 @@ public class RoundStatusDrawable extends StatusDrawable { private float progress; private int progressDirection = 1; + private Paint currentPaint; + + public RoundStatusDrawable(boolean createPaint) { + if (createPaint) { + currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + } + + @Override + public void setColor(int color) { + if (currentPaint != null) { + currentPaint.setColor(color); + } + } + public void setIsChat(boolean value) { isChat = value; } @@ -56,8 +72,9 @@ public class RoundStatusDrawable extends StatusDrawable { @Override public void draw(Canvas canvas) { - Theme.chat_statusPaint.setAlpha(55 + (int) (200 * progress)); - canvas.drawCircle(AndroidUtilities.dp(6), AndroidUtilities.dp(isChat ? 8 : 9), AndroidUtilities.dp(4), Theme.chat_statusPaint); + Paint paint = currentPaint == null ? Theme.chat_statusPaint : currentPaint; + paint.setAlpha(55 + (int) (200 * progress)); + canvas.drawCircle(AndroidUtilities.dp(6), AndroidUtilities.dp(isChat ? 8 : 9), AndroidUtilities.dp(4), paint); if (started) { update(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java index 79c65bfe7..ba1364c2a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchField.java @@ -144,6 +144,7 @@ public class SearchField extends FrameLayout { }); searchEditText.setOnEditorActionListener((v, actionId, event) -> { if (event != null && (event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH || event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) { + searchEditText.hideActionMode(); AndroidUtilities.hideKeyboard(searchEditText); } return false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java index c09d6fa12..0670a25d5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SearchViewPager.java @@ -2,6 +2,7 @@ package org.telegram.ui.Components; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; @@ -109,6 +110,10 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie int n = getChildCount(); loop: for (int i = 0; i < n; i++) { View v = getChildAt(i); + ViewHolder holder = searchListView.getChildViewHolder(v); + if (holder == null || holder.shouldIgnore()) { + continue; + } int position = searchlayoutManager.getPosition(v); for (int k = 0; k < currentAnimators.size(); k++) { if (currentAnimators.get(k).setup(v, position)) { @@ -155,7 +160,8 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie searchContainer.addView(searchListView); searchContainer.addView(noMediaFiltersSearchView); - FilteredSearchView.LoadingView loadingView = new FilteredSearchView.LoadingView(context); + FlickerLoadingView loadingView = new FlickerLoadingView(context); + loadingView.setViewType(1); emptyView = new StickerEmptyView(context, loadingView) { @Override public void setVisibility(int visibility) { @@ -663,9 +669,21 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie public void runResultsEnterAnimation() { Set hasSet = new HashSet<>(); int n = searchListView.getChildCount(); + View progressView = null; for (int i = 0; i < n; i++) { - hasSet.add(searchlayoutManager.getPosition(searchListView.getChildAt(i))); + View child = searchListView.getChildAt(i); + int childPosition = searchlayoutManager.getPosition(child); + if (child instanceof FlickerLoadingView) { + progressView = child; + } else { + hasSet.add(childPosition); + } } + final View finalProgressView = progressView; + if (progressView != null) { + searchListView.removeView(progressView); + } + searchListView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -685,6 +703,23 @@ public class SearchViewPager extends ViewPagerFixed implements FilteredSearchVie animator.valueAnimator.start(); } } + if (finalProgressView != null && finalProgressView.getParent() == null) { + searchListView.addView(finalProgressView); + RecyclerView.LayoutManager layoutManager = searchListView.getLayoutManager(); + if (layoutManager != null) { + layoutManager.ignoreView(finalProgressView); + Animator animator = ObjectAnimator.ofFloat(finalProgressView, ALPHA, finalProgressView.getAlpha(), 0); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finalProgressView.setAlpha(1f); + layoutManager.stopIgnoringView(finalProgressView); + searchListView.removeView(finalProgressView); + } + }); + animator.start(); + } + } return true; } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java index df83770ef..46161d9e9 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarView.java @@ -21,6 +21,8 @@ import android.view.View; import android.view.ViewConfiguration; import android.widget.FrameLayout; +import androidx.core.graphics.ColorUtils; + import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.ActionBar.Theme; @@ -43,6 +45,8 @@ public class SeekBarView extends FrameLayout { private long lastUpdateTime; private float currentRadius; private int[] pressedState = new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}; + private float transitionProgress = 1f; + private int transitionThumbX; public interface SeekBarViewDelegate { void onSeekBarDrag(boolean stop, float progress); @@ -72,8 +76,7 @@ public class SeekBarView extends FrameLayout { currentRadius = AndroidUtilities.dp(6); if (Build.VERSION.SDK_INT >= 21) { - int color = Theme.getColor(Theme.key_player_progress); - hoverDrawable = Theme.createSelectorDrawable(Color.argb(40, Color.red(color), Color.green(color), Color.blue(color)), 1, AndroidUtilities.dp(16)); + hoverDrawable = Theme.createSelectorDrawable(ColorUtils.setAlphaComponent(Theme.getColor(Theme.key_player_progress), 40), 1, AndroidUtilities.dp(16)); hoverDrawable.setCallback(this); hoverDrawable.setVisible(true, false); } @@ -116,7 +119,7 @@ public class SeekBarView extends FrameLayout { innerPaint1.setColor(inner); outerPaint1.setColor(outer); if (hoverDrawable != null) { - Theme.setDrawableColor(hoverDrawable, Color.argb(40, Color.red(outer), Color.green(outer), Color.blue(outer))); + Theme.setSelectorDrawableColor(hoverDrawable, ColorUtils.setAlphaComponent(outer, 40), true); } } @@ -127,7 +130,7 @@ public class SeekBarView extends FrameLayout { public void setOuterColor(int color) { outerPaint1.setColor(color); if (hoverDrawable != null) { - Theme.setDrawableColor(hoverDrawable, Color.argb(40, Color.red(color), Color.green(color), Color.blue(color))); + Theme.setSelectorDrawableColor(hoverDrawable, ColorUtils.setAlphaComponent(color, 40), true); } } @@ -246,6 +249,10 @@ public class SeekBarView extends FrameLayout { } public void setProgress(float progress) { + setProgress(progress, false); + } + + public void setProgress(float progress, boolean animated) { if (getMeasuredWidth() == 0) { progressToSet = progress; return; @@ -253,6 +260,10 @@ public class SeekBarView extends FrameLayout { progressToSet = -1; int newThumbX = (int) Math.ceil((getMeasuredWidth() - selectorWidth) * progress); if (thumbX != newThumbX) { + if (animated) { + transitionThumbX = thumbX; + transitionProgress = 0f; + } thumbX = newThumbX; if (thumbX < 0) { thumbX = 0; @@ -302,13 +313,14 @@ public class SeekBarView extends FrameLayout { hoverDrawable.setBounds(dx, dy, dx + AndroidUtilities.dp(32), dy + AndroidUtilities.dp(32)); hoverDrawable.draw(canvas); } + boolean needInvalidate = false; int newRad = AndroidUtilities.dp(pressed ? 8 : 6); + long newUpdateTime = SystemClock.elapsedRealtime(); + long dt = newUpdateTime - lastUpdateTime; + if (dt > 18) { + dt = 16; + } if (currentRadius != newRad) { - long newUpdateTime = SystemClock.elapsedRealtime(); - long dt = newUpdateTime - lastUpdateTime; - if (dt > 18) { - dt = 16; - } if (currentRadius < newRad) { currentRadius += AndroidUtilities.dp(1) * (dt / 60.0f); if (currentRadius > newRad) { @@ -320,9 +332,29 @@ public class SeekBarView extends FrameLayout { currentRadius = newRad; } } - invalidate(); + needInvalidate = true; + } + if (transitionProgress < 1f) { + transitionProgress += dt / 225f; + if (transitionProgress < 1f) { + needInvalidate = true; + } else { + transitionProgress = 1f; + } + } + if (transitionProgress < 1f) { + final float oldCircleProgress = 1f - Easings.easeInQuad.getInterpolation(Math.min(1f, transitionProgress * 3f)); + final float newCircleProgress = Easings.easeOutQuad.getInterpolation(transitionProgress); + if (oldCircleProgress > 0f) { + canvas.drawCircle(transitionThumbX + selectorWidth / 2, y + thumbSize / 2, currentRadius * oldCircleProgress, outerPaint1); + } + canvas.drawCircle(thumbX + selectorWidth / 2, y + thumbSize / 2, currentRadius * newCircleProgress, outerPaint1); + } else { + canvas.drawCircle(thumbX + selectorWidth / 2, y + thumbSize / 2, currentRadius, outerPaint1); + } + if (needInvalidate) { + postInvalidateOnAnimation(); } - canvas.drawCircle(thumbX + selectorWidth / 2, y + thumbSize / 2, currentRadius, outerPaint1); } public SeekBarAccessibilityDelegate getSeekBarAccessibilityDelegate() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java index a611e7cc3..b9908caec 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java @@ -10,6 +10,7 @@ package org.telegram.ui.Components; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Paint; import org.telegram.messenger.AndroidUtilities; import org.telegram.ui.ActionBar.Theme; @@ -21,6 +22,24 @@ public class SendingFileDrawable extends StatusDrawable { private boolean started = false; private float progress; + Paint currentPaint; + + public SendingFileDrawable(boolean createPaint) { + if (createPaint) { + currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + currentPaint.setStyle(Paint.Style.STROKE); + currentPaint.setStrokeCap(Paint.Cap.ROUND); + currentPaint.setStrokeWidth(AndroidUtilities.dp(2)); + } + } + + @Override + public void setColor(int color) { + if (currentPaint != null) { + currentPaint.setColor(color); + } + } + public void setIsChat(boolean value) { isChat = value; } @@ -51,17 +70,18 @@ public class SendingFileDrawable extends StatusDrawable { @Override public void draw(Canvas canvas) { + Paint paint = currentPaint == null ? Theme.chat_statusRecordPaint : currentPaint; for (int a = 0; a < 3; a++) { if (a == 0) { - Theme.chat_statusRecordPaint.setAlpha((int) (255 * progress)); + paint.setAlpha((int) (255 * progress)); } else if (a == 2) { - Theme.chat_statusRecordPaint.setAlpha((int) (255 * (1.0f - progress))); + paint.setAlpha((int) (255 * (1.0f - progress))); } else { - Theme.chat_statusRecordPaint.setAlpha(255); + paint.setAlpha(255); } float side = AndroidUtilities.dp(5) * a + AndroidUtilities.dp(5) * progress; - canvas.drawLine(side, AndroidUtilities.dp(isChat ? 3 : 4), side + AndroidUtilities.dp(4), AndroidUtilities.dp(isChat ? 7 : 8), Theme.chat_statusRecordPaint); - canvas.drawLine(side, AndroidUtilities.dp(isChat ? 11 : 12), side + AndroidUtilities.dp(4), AndroidUtilities.dp(isChat ? 7 : 8), Theme.chat_statusRecordPaint); + canvas.drawLine(side, AndroidUtilities.dp(isChat ? 3 : 4), side + AndroidUtilities.dp(4), AndroidUtilities.dp(isChat ? 7 : 8), paint); + canvas.drawLine(side, AndroidUtilities.dp(isChat ? 11 : 12), side + AndroidUtilities.dp(4), AndroidUtilities.dp(isChat ? 7 : 8), paint); } if (started) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java index 7c6c6483b..9477c3243 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -75,7 +75,7 @@ import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.ShareDialogCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; -import org.telegram.ui.ForwardsActivity; +import org.telegram.ui.MessageStatisticActivity; import java.util.ArrayList; import java.util.Collections; @@ -603,9 +603,16 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY - AndroidUtilities.dp(30)) { - dismiss(); - return true; + if (!fullHeight) { + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getY() < topOffset - AndroidUtilities.dp(30)) { + dismiss(); + return true; + } + } else { + if (ev.getAction() == MotionEvent.ACTION_DOWN && scrollOffsetY != 0 && ev.getY() < scrollOffsetY - AndroidUtilities.dp(30)) { + dismiss(); + return true; + } } return super.onInterceptTouchEvent(ev); } @@ -852,7 +859,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi }); containerView.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); - if (BuildVars.DEBUG_PRIVATE_VERSION && parentFragment != null && ChatObject.hasAdminRights(parentFragment.getCurrentChat()) && sendingMessageObjects.size() > 0 && sendingMessageObjects.get(0).messageOwner.forwards > 0) { + if (parentFragment != null && ChatObject.hasAdminRights(parentFragment.getCurrentChat()) && sendingMessageObjects.size() > 0 && sendingMessageObjects.get(0).messageOwner.forwards > 0) { MessageObject messageObject = sendingMessageObjects.get(0); if (!messageObject.isForwarded()) { sharesCountLayout = new LinearLayout(context); @@ -860,7 +867,7 @@ public class ShareAlert extends BottomSheet implements NotificationCenter.Notifi sharesCountLayout.setGravity(Gravity.CENTER_VERTICAL); sharesCountLayout.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector), 2)); containerView.addView(sharesCountLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 48, Gravity.RIGHT | Gravity.BOTTOM, 6, 0, -6, 0)); - sharesCountLayout.setOnClickListener(view -> parentFragment.presentFragment(new ForwardsActivity(messageObject))); + sharesCountLayout.setOnClickListener(view -> parentFragment.presentFragment(new MessageStatisticActivity(messageObject))); ImageView imageView = new ImageView(context); imageView.setImageResource(R.drawable.share_arrow); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java index 0927626f5..c37aabc5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SharedMediaLayout.java @@ -36,6 +36,10 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ChatObject; @@ -63,7 +67,6 @@ import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Adapters.FiltersView; import org.telegram.ui.Adapters.SearchAdapterHelper; import org.telegram.ui.ArticleViewer; import org.telegram.ui.Cells.ChatActionCell; @@ -80,7 +83,6 @@ import org.telegram.ui.Cells.SharedPhotoVideoCell; import org.telegram.ui.Cells.UserCell; import org.telegram.ui.ChatActivity; import org.telegram.ui.DialogsActivity; -import org.telegram.ui.FilteredSearchView; import org.telegram.ui.PhotoViewer; import org.telegram.ui.ProfileActivity; @@ -88,16 +90,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - @SuppressWarnings("unchecked") public class SharedMediaLayout extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { private static class MediaPage extends FrameLayout { private RecyclerListView listView; - private FilteredSearchView.LoadingView progressView; + private FlickerLoadingView progressView; private TextView emptyTextView; private ExtendedGridLayoutManager layoutManager; private ImageView emptyImageView; @@ -507,7 +505,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else if (view instanceof ContextLinkCell) { ContextLinkCell cell = (ContextLinkCell) view; MessageObject message = (MessageObject) cell.getParentObject(); - if (message != null && messageObject != null && message.getId() == messageObject.getId()) { + if (message != null && message.getId() == messageObject.getId()) { imageReceiver = cell.getPhotoImage(); cell.getLocationInWindow(coords); } @@ -1220,7 +1218,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter mediaPages[a].emptyTextView.setPadding(AndroidUtilities.dp(40), 0, AndroidUtilities.dp(40), AndroidUtilities.dp(128)); mediaPages[a].emptyView.addView(mediaPages[a].emptyTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 24, 0, 0)); - mediaPages[a].progressView = new FilteredSearchView.LoadingView(context) { + mediaPages[a].progressView = new FlickerLoadingView(context) { @Override public int getColumnsCount() { @@ -1228,7 +1226,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } @Override - public int getType() { + public int getViewType() { if (mediaPage.selectedType == 0 || mediaPage.selectedType == 5) { return 2; } else if (mediaPage.selectedType == 1) { @@ -1238,7 +1236,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else if (mediaPage.selectedType == 3) { return 5; } - return super.getType(); + return 1; } @Override @@ -1248,6 +1246,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter super.onDraw(canvas); } }; + mediaPages[a].progressView.showDate(false); mediaPages[a].progressView.setVisibility(View.GONE); mediaPages[a].addView(mediaPages[a].progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); if (a != 0) { @@ -1264,7 +1263,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter floatingDateView.setTranslationY(-AndroidUtilities.dp(48)); addView(floatingDateView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 48 + 4, 0, 0)); - addView(fragmentContextView = new FragmentContextView(context, parent, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); + addView(fragmentContextView = new FragmentContextView(context, parent, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); fragmentContextView.setSupportsCalls(false); fragmentContextView.setDelegate((start, show) -> { if (show && !start) { @@ -1607,7 +1606,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (lower_part != 0) { if (lower_part > 0) { args1.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { args1.putInt("chat_id", -lower_part); } } else { @@ -1637,7 +1636,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { TLRPC.Chat chat = profileActivity.getMessagesController().getChat(-lower_part); if (chat != null && chat.migrated_to != null) { args.putInt("migrated_to", lower_part); @@ -2069,8 +2068,21 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } else if (newItemCount < oldItemCount) { adapter.notifyItemRangeRemoved(newItemCount, (oldItemCount - newItemCount)); } - if (listView != null && oldItemCount == 0 && newItemCount > 0) { + if (listView != null && newItemCount > oldItemCount) { RecyclerListView finalListView = listView; + int n = finalListView.getChildCount(); + AnimatorSet animatorSet = new AnimatorSet(); + View progressView = null; + for (int i = 0; i < n; i++) { + View child = finalListView.getChildAt(i); + if (child instanceof FlickerLoadingView) { + progressView = child; + } + } + final View finalProgressView = progressView; + if (progressView != null) { + finalListView.removeView(progressView); + } getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -2079,14 +2091,34 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter AnimatorSet animatorSet = new AnimatorSet(); for (int i = 0; i < n; i++) { View child = finalListView.getChildAt(i); - child.setAlpha(0); - int s = Math.min(finalListView.getMeasuredHeight(), Math.max(0, child.getTop())); - int delay = (int) ((s / (float) finalListView.getMeasuredHeight()) * 100); - ObjectAnimator a = ObjectAnimator.ofFloat(child, View.ALPHA, 0, 1f); - a.setStartDelay(delay); - a.setDuration(200); - animatorSet.playTogether(a); + if (finalListView.getChildAdapterPosition(child) >= oldItemCount - 1) { + child.setAlpha(0); + int s = Math.min(finalListView.getMeasuredHeight(), Math.max(0, child.getTop())); + int delay = (int) ((s / (float) finalListView.getMeasuredHeight()) * 100); + ObjectAnimator a = ObjectAnimator.ofFloat(child, View.ALPHA, 0, 1f); + a.setStartDelay(delay); + a.setDuration(200); + animatorSet.playTogether(a); + } + if (finalProgressView != null && finalProgressView.getParent() == null) { + finalListView.addView(finalProgressView); + RecyclerView.LayoutManager layoutManager = finalListView.getLayoutManager(); + if (layoutManager != null) { + layoutManager.ignoreView(finalProgressView); + Animator animator = ObjectAnimator.ofFloat(finalProgressView, ALPHA, finalProgressView.getAlpha(), 0); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finalProgressView.setAlpha(1f); + layoutManager.stopIgnoringView(finalProgressView); + finalListView.removeView(finalProgressView); + } + }); + animator.start(); + } + } } + animatorSet.start(); return true; } @@ -2287,7 +2319,7 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter } } } - } else if (id == NotificationCenter.messagePlayingDidStart) { + } else { MessageObject messageObject = (MessageObject) args[0]; if (messageObject.eventId != 0) { return; @@ -3090,7 +3122,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter break; case 2: default: - view = new LoadingCell(mContext, AndroidUtilities.dp(32), AndroidUtilities.dp(54)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + flickerLoadingView.setIsSingleCell(true); + flickerLoadingView.showDate(false); + flickerLoadingView.setViewType(FlickerLoadingView.LINKS_TYPE); + view = flickerLoadingView; break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); @@ -3211,7 +3247,15 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter view = new SharedDocumentCell(mContext); break; case 2: - view = new LoadingCell(mContext, AndroidUtilities.dp(32), AndroidUtilities.dp(54)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + view = flickerLoadingView; + if (currentType == MediaDataController.MEDIA_MUSIC) { + flickerLoadingView.setViewType(FlickerLoadingView.AUDIO_TYPE); + } else { + flickerLoadingView.setViewType(FlickerLoadingView.FILES_TYPE); + } + flickerLoadingView.showDate(false); + flickerLoadingView.setIsSingleCell(true); break; case 3: default: @@ -3373,7 +3417,10 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter break; case 1: default: - view = new LoadingCell(mContext, AndroidUtilities.dp(32), AndroidUtilities.dp(74)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + flickerLoadingView.setIsSingleCell(true); + flickerLoadingView.setViewType(FlickerLoadingView.PHOTOS_TYPE); + view = flickerLoadingView; break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); @@ -3916,7 +3963,11 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter break; case 1: default: - view = new LoadingCell(mContext); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + flickerLoadingView.setIsSingleCell(true); + flickerLoadingView.showDate(false); + flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); + view = flickerLoadingView; break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); @@ -4085,45 +4136,43 @@ public class SharedMediaLayout extends FrameLayout implements NotificationCenter ArrayList resultArrayNames = new ArrayList<>(); ArrayList resultArray2 = new ArrayList<>(); - if (participantsCopy != null) { - for (int a = 0, N = participantsCopy.size(); a < N; a++) { - int userId; - TLObject o = participantsCopy.get(a); - if (o instanceof TLRPC.ChatParticipant) { - userId = ((TLRPC.ChatParticipant) o).user_id; - } else if (o instanceof TLRPC.ChannelParticipant) { - userId = ((TLRPC.ChannelParticipant) o).user_id; - } else { - continue; - } - TLRPC.User user = profileActivity.getMessagesController().getUser(userId); - if (user.id == profileActivity.getUserConfig().getClientUserId()) { - continue; + for (int a = 0, N = participantsCopy.size(); a < N; a++) { + int userId; + TLObject o = participantsCopy.get(a); + if (o instanceof TLRPC.ChatParticipant) { + userId = ((TLRPC.ChatParticipant) o).user_id; + } else if (o instanceof TLRPC.ChannelParticipant) { + userId = ((TLRPC.ChannelParticipant) o).user_id; + } else { + continue; + } + TLRPC.User user = profileActivity.getMessagesController().getUser(userId); + if (user.id == profileActivity.getUserConfig().getClientUserId()) { + continue; + } + + String name = UserObject.getUserName(user).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; } - String name = UserObject.getUserName(user).toLowerCase(); - String tName = LocaleController.getInstance().getTranslitString(name); - if (name.equals(tName)) { - tName = null; - } - - int found = 0; - for (String q : search) { - if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { - found = 1; - } else if (user.username != null && user.username.startsWith(q)) { - found = 2; - } - - if (found != 0) { - if (found == 1) { - resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); - } else { - resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); - } - resultArray2.add(o); - break; + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); } + resultArray2.add(o); + break; } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SlotsDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlotsDrawable.java new file mode 100644 index 000000000..482f3e4b0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlotsDrawable.java @@ -0,0 +1,432 @@ +package org.telegram.ui.Components; + +import android.graphics.Bitmap; +import android.text.TextUtils; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.DownloadController; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Cells.ChatMessageCell; + +import java.io.File; + +public class SlotsDrawable extends RLottieDrawable { + + enum ReelValue { + bar, + berries, + lemon, + seven, + sevenWin + } + + private ReelValue left; + private ReelValue center; + private ReelValue right; + + private long[] nativePtrs = new long[5]; + private int[] frameCounts = new int[5]; + private int[] frameNums = new int[5]; + private long[] secondNativePtrs = new long[3]; + private int[] secondFrameCounts = new int[3]; + private int[] secondFrameNums = new int[3]; + + public SlotsDrawable(String diceEmoji, int w, int h) { + super(diceEmoji, w, h); + + loadFrameRunnable = () -> { + if (isRecycled) { + return; + } + if (nativePtr == 0 || isDice == 2 && secondNativePtr == 0) { + if (frameWaitSync != null) { + frameWaitSync.countDown(); + } + uiHandler.post(uiRunnableNoFrame); + return; + } + if (backgroundBitmap == null) { + try { + backgroundBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + } catch (Throwable e) { + FileLog.e(e); + } + } + if (backgroundBitmap != null) { + try { + int result; + if (isDice == 1) { + result = -1; + for (int a = 0; a < nativePtrs.length; a++) { + result = getFrame(nativePtrs[a], frameNums[a], backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), a == 0); + if (a == 0) { + continue; + } + if (frameNums[a] + 1 < frameCounts[a]) { + frameNums[a]++; + } else if (a != 4) { + frameNums[a] = 0; + nextFrameIsLast = false; + if (secondNativePtr != 0) { + isDice = 2; + } + } + } + } else { + if (setLastFrame) { + for (int a = 0; a < secondFrameNums.length; a++) { + secondFrameNums[a] = secondFrameCounts[a] - 1; + } + } + if (autoRepeatPlayCount == 1) { + if (frameNums[0] + 1 < frameCounts[0]) { + frameNums[0]++; + } else { + frameNums[0] = -1; + } + } + getFrame(nativePtrs[0], Math.max(frameNums[0], 0), backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), true); + for (int a = 0; a < secondNativePtrs.length; a++) { + getFrame(secondNativePtrs[a], secondFrameNums[a] >= 0 ? secondFrameNums[a] : (secondFrameCounts[a] - 1), backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), false); + if (secondFrameNums[a] + 1 < secondFrameCounts[a]) { + secondFrameNums[a]++; + } else { + secondFrameNums[a] = -1; + } + } + result = getFrame(nativePtrs[4], frameNums[4], backgroundBitmap, width, height, backgroundBitmap.getRowBytes(), false); + if (frameNums[4] + 1 < frameCounts[4]) { + frameNums[4]++; + } + if (secondFrameNums[0] == -1 && secondFrameNums[1] == -1 && secondFrameNums[2] == -1) { + nextFrameIsLast = true; + } + if (left == right && right == center) { + if (secondFrameNums[0] == secondFrameCounts[0] - 100) { + if (autoRepeatPlayCount == 0) { + autoRepeatPlayCount++; + } + if (left == ReelValue.sevenWin) { + Runnable runnable = onFinishCallback.get(); + if (runnable != null) { + AndroidUtilities.runOnUIThread(runnable); + } + } + } + } else { + frameNums[0] = -1; + } + } + if (result == -1) { + uiHandler.post(uiRunnableNoFrame); + if (frameWaitSync != null) { + frameWaitSync.countDown(); + } + return; + } + nextRenderingBitmap = backgroundBitmap; + } catch (Exception e) { + FileLog.e(e); + } + } + uiHandler.post(uiRunnable); + if (frameWaitSync != null) { + frameWaitSync.countDown(); + } + }; + } + + private ReelValue reelValue(int rawValue) { + switch (rawValue) { + case 0: + return ReelValue.bar; + case 1: + return ReelValue.berries; + case 2: + return ReelValue.lemon; + case 3: + default: + return ReelValue.seven; + } + } + + private void init(int rawValue) { + rawValue--; + + int leftRawValue = rawValue & 3; + int centerRawValue = rawValue >> 2 & 3; + int rightRawValue = rawValue >> 4; + + ReelValue leftReelValue = reelValue(leftRawValue); + ReelValue centerReelValue = reelValue(centerRawValue); + ReelValue rightReelValue = reelValue(rightRawValue); + + if (leftReelValue == ReelValue.seven && centerReelValue == ReelValue.seven && rightReelValue == ReelValue.seven) { + leftReelValue = ReelValue.sevenWin; + centerReelValue = ReelValue.sevenWin; + rightReelValue = ReelValue.sevenWin; + } + + left = leftReelValue; + center = centerReelValue; + right = rightReelValue; + } + + private boolean is777() { + return left == ReelValue.sevenWin && center == ReelValue.sevenWin && right == ReelValue.sevenWin; + } + + public boolean setBaseDice(ChatMessageCell messageCell, TLRPC.TL_messages_stickerSet stickerSet) { + if (nativePtr != 0 || loadingInBackground) { + return true; + } + loadingInBackground = true; + MessageObject currentMessageObject = messageCell.getMessageObject(); + int account = messageCell.getMessageObject().currentAccount; + Utilities.globalQueue.postRunnable(() -> { + if (destroyAfterLoading) { + AndroidUtilities.runOnUIThread(() -> { + loadingInBackground = false; + if (!secondLoadingInBackground && destroyAfterLoading) { + recycle(); + } + }); + return; + } + boolean loading = false; + for (int a = 0; a < nativePtrs.length; a++) { + if (nativePtrs[a] != 0) { + continue; + } + int num; + if (a == 0) { + num = 1; + } else if (a == 1) { + num = 8; + } else if (a == 2) { + num = 14; + } else if (a == 3) { + num = 20; + } else { + num = 2; + } + TLRPC.Document document = stickerSet.documents.get(num); + File path = FileLoader.getPathToAttach(document, true); + String json = readRes(path, 0); + if (TextUtils.isEmpty(json)) { + loading = true; + AndroidUtilities.runOnUIThread(() -> { + String fileName = FileLoader.getAttachFileName(document); + DownloadController.getInstance(account).addLoadingFileObserver(fileName, currentMessageObject, messageCell); + FileLoader.getInstance(account).loadFile(document, stickerSet, 1, 1); + }); + } else { + nativePtrs[a] = createWithJson(json, "dice", metaData, null); + frameCounts[a] = metaData[0]; + } + } + if (loading) { + AndroidUtilities.runOnUIThread(() -> loadingInBackground = false); + return; + } + AndroidUtilities.runOnUIThread(() -> { + loadingInBackground = false; + if (!secondLoadingInBackground && destroyAfterLoading) { + recycle(); + return; + } + nativePtr = nativePtrs[0]; + DownloadController.getInstance(account).removeLoadingFileObserver(messageCell); + timeBetweenFrames = Math.max(16, (int) (1000.0f / metaData[1])); + scheduleNextGetFrame(); + invalidateInternal(); + }); + }); + + return true; + } + + public boolean setDiceNumber(ChatMessageCell messageCell, int number, TLRPC.TL_messages_stickerSet stickerSet, boolean instant) { + if (secondNativePtr != 0 || secondLoadingInBackground) { + return true; + } + init(number); + MessageObject currentMessageObject = messageCell.getMessageObject(); + int account = messageCell.getMessageObject().currentAccount; + + secondLoadingInBackground = true; + Utilities.globalQueue.postRunnable(() -> { + if (destroyAfterLoading) { + AndroidUtilities.runOnUIThread(() -> { + secondLoadingInBackground = false; + if (!loadingInBackground && destroyAfterLoading) { + recycle(); + } + }); + return; + } + + boolean loading = false; + for (int a = 0; a < secondNativePtrs.length + 2; a++) { + int num; + if (a <= 2) { + if (secondNativePtrs[a] != 0) { + continue; + } + if (a == 0) { + if (left == ReelValue.bar) { + num = 5; + } else if (left == ReelValue.berries) { + num = 6; + } else if (left == ReelValue.lemon) { + num = 7; + } else if (left == ReelValue.seven) { + num = 4; + } else { + num = 3; + } + } else if (a == 1) { + if (center == ReelValue.bar) { + num = 11; + } else if (center == ReelValue.berries) { + num = 12; + } else if (center == ReelValue.lemon) { + num = 13; + } else if (center == ReelValue.seven) { + num = 10; + } else { + num = 9; + } + } else { + if (right == ReelValue.bar) { + num = 17; + } else if (right == ReelValue.berries) { + num = 18; + } else if (right == ReelValue.lemon) { + num = 19; + } else if (right == ReelValue.seven) { + num = 16; + } else { + num = 15; + } + } + } else { + if (nativePtrs[a] != 0) { + continue; + } + if (a == 3) { + num = 1; + } else { + num = 2; + } + } + TLRPC.Document document = stickerSet.documents.get(num); + File path = FileLoader.getPathToAttach(document, true); + String json = readRes(path, 0); + if (TextUtils.isEmpty(json)) { + loading = true; + AndroidUtilities.runOnUIThread(() -> { + String fileName = FileLoader.getAttachFileName(document); + DownloadController.getInstance(account).addLoadingFileObserver(fileName, currentMessageObject, messageCell); + FileLoader.getInstance(account).loadFile(document, stickerSet, 1, 1); + }); + } else { + if (a <= 2) { + secondNativePtrs[a] = createWithJson(json, "dice", metaData, null); + secondFrameCounts[a] = metaData[0]; + } else { + nativePtrs[a == 3 ? 0 : 4] = createWithJson(json, "dice", metaData, null); + frameCounts[a == 3 ? 0 : 4] = metaData[0]; + } + } + } + if (loading) { + AndroidUtilities.runOnUIThread(() -> secondLoadingInBackground = false); + return; + } + AndroidUtilities.runOnUIThread(() -> { + if (instant && nextRenderingBitmap == null && renderingBitmap == null && loadFrameTask == null) { + isDice = 2; + setLastFrame = true; + } + secondLoadingInBackground = false; + if (!loadingInBackground && destroyAfterLoading) { + recycle(); + return; + } + secondNativePtr = secondNativePtrs[0]; + DownloadController.getInstance(account).removeLoadingFileObserver(messageCell); + timeBetweenFrames = Math.max(16, (int) (1000.0f / metaData[1])); + scheduleNextGetFrame(); + invalidateInternal(); + }); + }); + return true; + } + + @Override + public void recycle() { + isRunning = false; + isRecycled = true; + checkRunningTasks(); + if (loadingInBackground || secondLoadingInBackground) { + destroyAfterLoading = true; + } else if (loadFrameTask == null && cacheGenerateTask == null) { + for (int a = 0; a < nativePtrs.length; a++) { + if (nativePtrs[a] != 0) { + if (nativePtrs[a] == nativePtr) { + nativePtr = 0; + } + destroy(nativePtrs[a]); + nativePtrs[a] = 0; + } + } + for (int a = 0; a < secondNativePtrs.length; a++) { + if (secondNativePtrs[a] != 0) { + if (secondNativePtrs[a] == secondNativePtr) { + secondNativePtr = 0; + } + destroy(secondNativePtrs[a]); + secondNativePtrs[a] = 0; + } + } + recycleResources(); + } else { + destroyWhenDone = true; + } + } + + @Override + protected void decodeFrameFinishedInternal() { + if (destroyWhenDone) { + checkRunningTasks(); + if (loadFrameTask == null && cacheGenerateTask == null) { + for (int a = 0; a < nativePtrs.length; a++) { + if (nativePtrs[a] != 0) { + destroy(nativePtrs[a]); + nativePtrs[a] = 0; + } + } + for (int a = 0; a < secondNativePtrs.length; a++) { + if (secondNativePtrs[a] != 0) { + destroy(secondNativePtrs[a]); + secondNativePtrs[a] = 0; + } + } + } + } + if (nativePtr == 0 && secondNativePtr == 0) { + recycleResources(); + return; + } + waitingForNextTask = true; + if (!hasParentView()) { + stop(); + } + scheduleNextGetFrame(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusDrawable.java index e3bf3ae77..3381e69f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StatusDrawable.java @@ -8,10 +8,12 @@ package org.telegram.ui.Components; +import android.graphics.Paint; import android.graphics.drawable.Drawable; public abstract class StatusDrawable extends Drawable { public abstract void start(); public abstract void stop(); public abstract void setIsChat(boolean value); + public abstract void setColor(int color); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SvgHelper.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SvgHelper.java index 15401aea1..4f8a4964d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SvgHelper.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SvgHelper.java @@ -25,10 +25,14 @@ package org.telegram.ui.Components; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.Drawable; import org.telegram.messenger.FileLog; import org.xml.sax.Attributes; @@ -47,12 +51,109 @@ import javax.xml.parsers.SAXParserFactory; public class SvgHelper { + private static class Line { + float x1, y1, x2, y2; + + public Line(float x1, float y1, float x2, float y2) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } + } + + private static class Circle { + float x1, y1, rad; + + public Circle(float x1, float y1, float rad) { + this.x1 = x1; + this.y1 = y1; + this.rad = rad; + } + } + + private static class Oval { + RectF rect; + + public Oval(RectF rect) { + this.rect = rect; + } + } + + public static class SvgDrawable extends Drawable { + + private ArrayList commands = new ArrayList<>(); + private HashMap paints = new HashMap<>(); + private int width; + private int height; + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + float scaleX = bounds.width() / (float) width; + float scaleY = bounds.height() / (float) height; + float scale = Math.max(scaleX, scaleY); + canvas.scale(scale, scale); + for (int a = 0, N = commands.size(); a < N; a++) { + Object object = commands.get(a); + if (object instanceof Matrix) { + canvas.save(); + canvas.concat((Matrix) object); + } else if (object == null) { + canvas.restore(); + } else { + Paint paint = paints.get(object); + if (object instanceof Path) { + canvas.drawPath((Path) object, paint); + } else if (object instanceof Rect) { + canvas.drawRect((Rect) object, paint); + } else if (object instanceof RectF) { + canvas.drawRect((RectF) object, paint); + } else if (object instanceof Line) { + Line line = (Line) object; + canvas.drawLine(line.x1, line.y1, line.x2, line.y2, paint); + } else if (object instanceof Circle) { + Circle circle = (Circle) object; + canvas.drawCircle(circle.x1, circle.y1, circle.rad, paint); + } else if (object instanceof Oval) { + Oval oval = (Oval) object; + canvas.drawOval(oval.rect, paint); + } + } + } + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + private void addCommand(Object command, Paint paint) { + commands.add(command); + paints.put(command, new Paint(paint)); + } + + private void addCommand(Object command) { + commands.add(command); + } + } + public static Bitmap getBitmap(File file, int width, int height, boolean white) { try (FileInputStream stream = new FileInputStream(file)) { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - SVGHandler handler = new SVGHandler(width, height, white); + SVGHandler handler = new SVGHandler(width, height, white, false); xr.setContentHandler(handler); xr.parse(new InputSource(stream)); return handler.getBitmap(); @@ -67,7 +168,7 @@ public class SvgHelper { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - SVGHandler handler = new SVGHandler(width, height, white); + SVGHandler handler = new SVGHandler(width, height, white, false); xr.setContentHandler(handler); xr.parse(new InputSource(new StringReader(xml))); return handler.getBitmap(); @@ -77,6 +178,21 @@ public class SvgHelper { } } + public static SvgDrawable getDrawable(String xml) { + try { + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser sp = spf.newSAXParser(); + XMLReader xr = sp.getXMLReader(); + SVGHandler handler = new SVGHandler(0, 0, false, true); + xr.setContentHandler(handler); + xr.parse(new InputSource(new StringReader(xml))); + return handler.getDrawable(); + } catch (Exception e) { + FileLog.e(e); + return null; + } + } + public static Bitmap getBitmapByPathOnly(String pathString, int svgWidth, int svgHeight, int width, int height) { try { Path path = doPath(pathString); @@ -632,6 +748,7 @@ public class SvgHelper { private Canvas canvas; private Bitmap bitmap; + private SvgDrawable drawable; private int desiredWidth; private int desiredHeight; private float scale = 1.0f; @@ -643,10 +760,13 @@ public class SvgHelper { private HashMap globalStyles = new HashMap<>(); - private SVGHandler(int dw, int dh, boolean white) { + private SVGHandler(int dw, int dh, boolean white, boolean asDrawable) { desiredWidth = dw; desiredHeight = dh; whiteOnly = white; + if (asDrawable) { + drawable = new SvgDrawable(); + } } @Override @@ -678,7 +798,7 @@ public class SvgHelper { if (whiteOnly) { paint.setColor(0xffffffff); } else { - paint.setColor(0xFF000000); + paint.setColor(0xff000000); } return true; } @@ -746,14 +866,22 @@ public class SvgHelper { pushed = transform != null; if (pushed) { final Matrix matrix = parseTransform(transform); - canvas.save(); - canvas.concat(matrix); + if (drawable != null) { + drawable.addCommand(matrix); + } else { + canvas.save(); + canvas.concat(matrix); + } } } private void popTransform() { if (pushed) { - canvas.restore(); + if (drawable != null) { + drawable.addCommand(null); + } else { + canvas.restore(); + } } } @@ -783,16 +911,21 @@ public class SvgHelper { if (width == 0 || height == 0) { width = desiredWidth; height = desiredHeight; - } else { + } else if (desiredWidth != 0 && desiredHeight != 0) { scale = Math.min(desiredWidth / (float) width, desiredHeight / (float) height); width *= scale; height *= scale; } - bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - bitmap.eraseColor(0); - canvas = new Canvas(bitmap); - if (scale != 0) { - canvas.scale(scale, scale); + if (drawable == null) { + bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.eraseColor(0); + canvas = new Canvas(bitmap); + if (scale != 0) { + canvas.scale(scale, scale); + } + } else { + drawable.width = width; + drawable.height = height; } break; } @@ -822,10 +955,18 @@ public class SvgHelper { pushTransform(atts); Properties props = new Properties(atts, globalStyles); if (doFill(props)) { - canvas.drawRect(x, y, x + width, y + height, paint); + if (drawable != null) { + drawable.addCommand(new RectF(x, y, x + width, y + height), paint); + } else { + canvas.drawRect(x, y, x + width, y + height, paint); + } } if (doStroke(props)) { - canvas.drawRect(x, y, x + width, y + height, paint); + if (drawable != null) { + drawable.addCommand(new RectF(x, y, x + width, y + height), paint); + } else { + canvas.drawRect(x, y, x + width, y + height, paint); + } } popTransform(); break; @@ -838,7 +979,11 @@ public class SvgHelper { Properties props = new Properties(atts, globalStyles); if (doStroke(props)) { pushTransform(atts); - canvas.drawLine(x1, y1, x2, y2, paint); + if (drawable != null) { + drawable.addCommand(new Line(x1, y1, x2, y2), paint); + } else { + canvas.drawLine(x1, y1, x2, y2, paint); + } popTransform(); } break; @@ -851,10 +996,18 @@ public class SvgHelper { pushTransform(atts); Properties props = new Properties(atts, globalStyles); if (doFill(props)) { - canvas.drawCircle(centerX, centerY, radius, paint); + if (drawable != null) { + drawable.addCommand(new Circle(centerX, centerY, radius), paint); + } else { + canvas.drawCircle(centerX, centerY, radius, paint); + } } if (doStroke(props)) { - canvas.drawCircle(centerX, centerY, radius, paint); + if (drawable != null) { + drawable.addCommand(new Circle(centerX, centerY, radius), paint); + } else { + canvas.drawCircle(centerX, centerY, radius, paint); + } } popTransform(); } @@ -870,10 +1023,18 @@ public class SvgHelper { Properties props = new Properties(atts, globalStyles); rect.set(centerX - radiusX, centerY - radiusY, centerX + radiusX, centerY + radiusY); if (doFill(props)) { - canvas.drawOval(rect, paint); + if (drawable != null) { + drawable.addCommand(new Oval(rect), paint); + } else { + canvas.drawOval(rect, paint); + } } if (doStroke(props)) { - canvas.drawOval(rect, paint); + if (drawable != null) { + drawable.addCommand(new Oval(rect), paint); + } else { + canvas.drawOval(rect, paint); + } } popTransform(); } @@ -898,10 +1059,18 @@ public class SvgHelper { p.close(); } if (doFill(props)) { - canvas.drawPath(p, paint); + if (drawable != null) { + drawable.addCommand(p, paint); + } else { + canvas.drawPath(p, paint); + } } if (doStroke(props)) { - canvas.drawPath(p, paint); + if (drawable != null) { + drawable.addCommand(p, paint); + } else { + canvas.drawPath(p, paint); + } } popTransform(); } @@ -912,10 +1081,18 @@ public class SvgHelper { pushTransform(atts); Properties props = new Properties(atts, globalStyles); if (doFill(props)) { - canvas.drawPath(p, paint); + if (drawable != null) { + drawable.addCommand(p, paint); + } else { + canvas.drawPath(p, paint); + } } if (doStroke(props)) { - canvas.drawPath(p, paint); + if (drawable != null) { + drawable.addCommand(p, paint); + } else { + canvas.drawPath(p, paint); + } } popTransform(); break; @@ -965,6 +1142,10 @@ public class SvgHelper { public Bitmap getBitmap() { return bitmap; } + + public SvgDrawable getDrawable() { + return drawable; + } } private static final double[] pow10 = new double[128]; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersAlert.java index 3f303f55b..053f1127f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersAlert.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersAlert.java @@ -66,7 +66,9 @@ public class TrendingStickersAlert extends BottomSheet { } AndroidUtilities.hideKeyboard(view); } - updateLayout(); + if (dy != 0) { + updateLayout(); + } } }); } @@ -147,7 +149,6 @@ public class TrendingStickersAlert extends BottomSheet { TrendingStickersAlert.this.setAllowNestedScroll(false); gluedToTop = true; } - layout.setContentViewPaddingBottom(keyboardHeight); } } }); @@ -175,8 +176,13 @@ public class TrendingStickersAlert extends BottomSheet { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { final int statusBarHeight = Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0; - final int height = MeasureSpec.getSize(heightMeasureSpec) - statusBarHeight; + final int height = MeasureSpec.getSize(getMeasuredHeight()) - statusBarHeight; final int keyboardHeight = measureKeyboardHeight(); final int padding = (int) ((height + keyboardHeight) * 0.2f); @@ -187,22 +193,15 @@ public class TrendingStickersAlert extends BottomSheet { gluedToTop = true; } else { layout.glueToTop(false); - layout.setContentViewPaddingTop(padding); TrendingStickersAlert.this.setAllowNestedScroll(true); gluedToTop = false; } - layout.setContentViewPaddingBottom(keyboardHeight); + layout.setContentViewPaddingTop(padding); if (getPaddingTop() != statusBarHeight) { setPadding(backgroundPaddingLeft, statusBarHeight, backgroundPaddingLeft, 0); } ignoreLayout = false; - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY)); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - updateLayout(); + super.onLayout(changed, l, t, r, b); } @Override @@ -214,6 +213,7 @@ public class TrendingStickersAlert extends BottomSheet { @Override protected void onDraw(Canvas canvas) { + updateLayout(); super.onDraw(canvas); final float fraction = getFraction(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersLayout.java index 47244f3b5..0e473ee89 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TrendingStickersLayout.java @@ -138,10 +138,16 @@ public class TrendingStickersLayout extends FrameLayout implements NotificationC @Override public void setAdapterVisible(boolean visible) { + boolean changed = false; if (visible && listView.getAdapter() != searchAdapter) { listView.setAdapter(searchAdapter); + changed = true; } else if (!visible && listView.getAdapter() != adapter) { listView.setAdapter(adapter); + changed = true; + } + if (changed && listView.getAdapter().getItemCount() > 0) { + layoutManager.scrollToPositionWithOffset(0, -listView.getPaddingTop() + AndroidUtilities.dp(58) + topOffset, false); } } @@ -261,6 +267,22 @@ public class TrendingStickersLayout extends FrameLayout implements NotificationC if (glueToTopAnimator != null) { return 0; } + if (gluedToTop) { + int minPosition = 1; + for (int i = 0; i < getChildCount(); i++) { + int p = listView.getChildAdapterPosition(getChildAt(i)); + if (p < minPosition) { + minPosition = p; + break; + } + } + if (minPosition == 0) { + View minView = layoutManager.findViewByPosition(minPosition); + if (minView != null && minView.getTop() - dy > AndroidUtilities.dp(58)) { + dy = minView.getTop() - AndroidUtilities.dp(58); + } + } + } return super.scrollVerticallyBy(dy, recycler, state); } }); @@ -448,16 +470,7 @@ public class TrendingStickersLayout extends FrameLayout implements NotificationC paddingTop += AndroidUtilities.dp(58); if (listView.getPaddingTop() != paddingTop) { ignoreLayout = true; - listView.setPadding(0, paddingTop, 0, listView.getPaddingBottom()); - ignoreLayout = false; - } - } - - public void setContentViewPaddingBottom(int paddingBottom) { - if (listView.getPaddingBottom() != paddingBottom) { - ignoreLayout = true; - listView.setPadding(0, listView.getPaddingTop(), 0, paddingBottom); - updateLastItemInAdapter(); + listView.setPadding(0, paddingTop, 0, 0); ignoreLayout = false; } } @@ -481,6 +494,12 @@ public class TrendingStickersLayout extends FrameLayout implements NotificationC return true; } View child = listView.getChildAt(0); + for (int i = 1; i < listView.getChildCount(); i++) { + View view = listView.getChildAt(i); + if (view.getTop() < child.getTop()) { + child = view; + } + } RecyclerListView.Holder holder = (RecyclerListView.Holder) listView.findContainingViewHolder(child); int top = child.getTop() - AndroidUtilities.dp(58); int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; @@ -546,7 +565,6 @@ public class TrendingStickersLayout extends FrameLayout implements NotificationC glueToTopAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - setContentViewPaddingTop(0); glueToTopAnimator = null; } }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java index 2977e7547..89fef73bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java @@ -10,6 +10,7 @@ package org.telegram.ui.Components; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.Paint; import android.graphics.PixelFormat; import android.view.animation.DecelerateInterpolator; @@ -29,6 +30,21 @@ public class TypingDotsDrawable extends StatusDrawable { private boolean started = false; private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); + private Paint currentPaint; + + public TypingDotsDrawable(boolean createPaint) { + if (createPaint) { + currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + } + + @Override + public void setColor(int color) { + if (currentPaint != null) { + currentPaint.setColor(color); + } + } + public void setIsChat(boolean value) { isChat = value; } @@ -91,10 +107,17 @@ public class TypingDotsDrawable extends StatusDrawable { } else { y = AndroidUtilities.dp(9.3f) + getBounds().top; } - Theme.chat_statusPaint.setAlpha(255); - canvas.drawCircle(AndroidUtilities.dp(3), y, scales[0] * AndroidUtilities.density, Theme.chat_statusPaint); - canvas.drawCircle(AndroidUtilities.dp(9), y, scales[1] * AndroidUtilities.density, Theme.chat_statusPaint); - canvas.drawCircle(AndroidUtilities.dp(15), y, scales[2] * AndroidUtilities.density, Theme.chat_statusPaint); + Paint paint; + if (currentPaint == null) { + paint = Theme.chat_statusPaint; + paint.setAlpha(255); + } else { + paint = currentPaint; + } + + canvas.drawCircle(AndroidUtilities.dp(3), y, scales[0] * AndroidUtilities.density, paint); + canvas.drawCircle(AndroidUtilities.dp(9), y, scales[1] * AndroidUtilities.density, paint); + canvas.drawCircle(AndroidUtilities.dp(15), y, scales[2] * AndroidUtilities.density, paint); checkUpdate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java index 19ac02d6c..195bf482b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/UndoView.java @@ -106,6 +106,8 @@ public class UndoView extends FrameLayout { public final static int ACTION_REMOVED_FROM_FOLDER = 21; public final static int ACTION_PROFILE_PHOTO_CHANGED = 22; public final static int ACTION_CHAT_UNARCHIVED = 23; + public final static int ACTION_PROXIMITY_SET = 24; + public final static int ACTION_PROXIMITY_REMOVED = 25; private CharSequence infoText; @@ -235,13 +237,13 @@ public class UndoView extends FrameLayout { } private boolean hasSubInfo() { - return currentAction == ACTION_QR_SESSION_ACCEPTED || currentAction == ACTION_ARCHIVE_HIDDEN || currentAction == ACTION_ARCHIVE_HINT || currentAction == ACTION_ARCHIVE_FEW_HINT || + return currentAction == ACTION_QR_SESSION_ACCEPTED || currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_ARCHIVE_HIDDEN || currentAction == ACTION_ARCHIVE_HINT || currentAction == ACTION_ARCHIVE_FEW_HINT || currentAction == ACTION_QUIZ_CORRECT || currentAction == ACTION_QUIZ_INCORRECT || currentAction == ACTION_ARCHIVE_PINNED && MessagesController.getInstance(currentAccount).dialogFilters.isEmpty(); } public boolean isMultilineSubInfo() { - return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE; + return currentAction == ACTION_THEME_CHANGED || currentAction == ACTION_FILTERS_AVAILABLE || currentAction == ACTION_PROXIMITY_SET; } public void setAdditionalTranslationY(float value) { @@ -518,6 +520,59 @@ public class UndoView extends FrameLayout { leftImageView.setProgress(0); leftImageView.playAnimation(); } + } else if (currentAction == ACTION_PROXIMITY_SET || currentAction == ACTION_PROXIMITY_REMOVED) { + int radius = (Integer) infoObject; + TLRPC.User user = (TLRPC.User) infoObject2; + + undoImageView.setVisibility(GONE); + leftImageView.setVisibility(VISIBLE); + + if (radius != 0) { + infoTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + leftImageView.clearLayerColors(); + leftImageView.setLayerColor("BODY.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Wibe Big.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Wibe Big 3.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Wibe Small.**", Theme.getColor(Theme.key_undo_infoColor)); + + infoTextView.setText(LocaleController.getString("ProximityAlertSet", R.string.ProximityAlertSet)); + leftImageView.setAnimation(R.raw.ic_unmute, 28, 28); + subinfoTextView.setVisibility(VISIBLE); + subinfoTextView.setSingleLine(false); + subinfoTextView.setMaxLines(3); + + if (user != null) { + subinfoTextView.setText(LocaleController.formatString("ProximityAlertSetInfoUser", R.string.ProximityAlertSetInfoUser, UserObject.getFirstName(user), LocaleController.formatDistance(radius, 2))); + } else { + subinfoTextView.setText(LocaleController.formatString("ProximityAlertSetInfoGroup2", R.string.ProximityAlertSetInfoGroup2, LocaleController.formatDistance(radius, 2))); + } + undoButton.setVisibility(GONE); + + layoutParams.topMargin = AndroidUtilities.dp(6); + } else { + infoTextView.setTypeface(Typeface.DEFAULT); + infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + leftImageView.clearLayerColors(); + leftImageView.setLayerColor("Body Main.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Body Top.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Line.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Curve Big.**", Theme.getColor(Theme.key_undo_infoColor)); + leftImageView.setLayerColor("Curve Small.**", Theme.getColor(Theme.key_undo_infoColor)); + + layoutParams.topMargin = AndroidUtilities.dp(14); + + infoTextView.setText(LocaleController.getString("ProximityAlertCancelled", R.string.ProximityAlertCancelled)); + leftImageView.setAnimation(R.raw.ic_mute, 28, 28); + subinfoTextView.setVisibility(GONE); + undoTextView.setTextColor(Theme.getColor(Theme.key_undo_cancelColor)); + undoButton.setVisibility(VISIBLE); + } + + layoutParams.leftMargin = AndroidUtilities.dp(58); + + leftImageView.setProgress(0); + leftImageView.playAnimation(); } else if (currentAction == ACTION_QR_SESSION_ACCEPTED) { TLRPC.TL_authorization authorization = (TLRPC.TL_authorization) infoObject; @@ -744,6 +799,8 @@ public class UndoView extends FrameLayout { undoViewHeight = infoTextView.getMeasuredHeight() + AndroidUtilities.dp(currentAction == ACTION_DICE_INFO || currentAction == ACTION_DICE_NO_SEND_INFO || currentAction == ACTION_TEXT_INFO ? 14 : 28); if (currentAction == ACTION_TEXT_INFO) { undoViewHeight = Math.max(undoViewHeight, AndroidUtilities.dp(52)); + } else if (currentAction == ACTION_PROXIMITY_REMOVED) { + undoViewHeight = Math.max(undoViewHeight, AndroidUtilities.dp(50)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java index 65692218a..0cbf97fdd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/VideoPlayer.java @@ -128,11 +128,17 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid private boolean looping; private int repeatCount; + private boolean shouldPauseOther; + Handler audioUpdateHandler = new Handler(Looper.getMainLooper()); private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); public VideoPlayer() { + this(true); + } + + public VideoPlayer(boolean pauseOther) { mediaDataSourceFactory = new ExtendedDefaultDataSourceFactory(ApplicationLoader.applicationContext, BANDWIDTH_METER, new DefaultHttpDataSourceFactory("Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20150101 Firefox/47.0 (Chrome)", BANDWIDTH_METER)); mainHandler = new Handler(); @@ -141,7 +147,10 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); lastReportedPlaybackState = ExoPlayer.STATE_IDLE; - NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.playerDidStartPlaying); + shouldPauseOther = pauseOther; + if (pauseOther) { + NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.playerDidStartPlaying); + } } @Override @@ -339,7 +348,9 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid audioPlayer.release(async); audioPlayer = null; } - NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.playerDidStartPlaying); + if (shouldPauseOther) { + NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.playerDidStartPlaying); + } } @Override @@ -572,7 +583,7 @@ public class VideoPlayer implements ExoPlayer.EventListener, SimpleExoPlayer.Vid @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { maybeReportPlayerState(); - if (playWhenReady && playbackState == Player.STATE_READY && !isMuted()) { + if (playWhenReady && playbackState == Player.STATE_READY && !isMuted() && shouldPauseOther) { NotificationCenter.getGlobalInstance().postNotificationName(NotificationCenter.playerDidStartPlaying, this); } if (!videoPlayerReady && playbackState == Player.STATE_READY) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java index 615cae93e..49b0cff47 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/VoIPToggleButton.java @@ -6,7 +6,6 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -14,7 +13,6 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.Drawable; -import android.graphics.drawable.RippleDrawable; import android.view.Gravity; import android.view.View; import android.view.accessibility.AccessibilityNodeInfo; @@ -290,7 +288,7 @@ public class VoIPToggleButton extends FrameLayout { textView[1].setVisibility(View.GONE); } - if (!iconChangeColor) { + if (!iconChangeColor && icon[1] != null) { icon[0] = icon[1]; icon[1] = null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java index 21d690b9c..d0337ac1d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -514,7 +514,7 @@ private int lastMeasuredTopPadding; if (inPreviewMode) { top = AndroidUtilities.statusBarHeight; } else { - top = inPreviewMode ? 0 : (int) (-getY() + actionBar.getY()); + top = (int) (-getY() + actionBar.getY()); } if (whiteActionBar) { if (searchAnimationProgress == 1f) { @@ -2834,11 +2834,11 @@ private int lastMeasuredTopPadding; if (!onlySelect && initialDialogsType == 0) { fragmentLocationContextView = new FragmentContextView(context, this, true); - fragmentLocationContextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + fragmentLocationContextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); contentView.addView(fragmentLocationContextView); fragmentContextView = new FragmentContextView(context, this, false); - fragmentContextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + fragmentContextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); contentView.addView(fragmentContextView); fragmentContextView.setAdditionalContextView(fragmentLocationContextView); @@ -3363,7 +3363,7 @@ private int lastMeasuredTopPadding; } private void updateFilterTabs(boolean force) { - if (filterTabsView == null || inPreviewMode) { + if (filterTabsView == null || inPreviewMode || searchIsShowed) { return; } if (scrimPopupWindow != null) { @@ -3807,6 +3807,9 @@ private int lastMeasuredTopPadding; animators.add(ObjectAnimator.ofFloat(searchViewPager, View.SCALE_X, show ? 1.0f : 1.05f)); animators.add(ObjectAnimator.ofFloat(searchViewPager, View.SCALE_Y, show ? 1.0f : 1.05f)); animators.add(ObjectAnimator.ofFloat(searchItem.getIconView(), View.ALPHA, show ? 0 : 1f)); + if (passcodeItem != null) { + animators.add(ObjectAnimator.ofFloat(passcodeItem.getIconView(), View.ALPHA, show ? 0 : 1f)); + } animators.add(ObjectAnimator.ofFloat(searchItem.getSearchContainer(), View.ALPHA, show ? 1f : 0)); if (filterTabsView != null && filterTabsView.getVisibility() == View.VISIBLE) { @@ -4940,7 +4943,7 @@ private int lastMeasuredTopPadding; if (MessagesController.isSupportUser(user)) { cantBlockCount++; } else { - if (lower_id == 0 || preferences.getBoolean("dialog_bar_report" + selectedDialog, true)) { + if (preferences.getBoolean("dialog_bar_report" + selectedDialog, true)) { canReportSpamCount++; } } @@ -5656,7 +5659,7 @@ private int lastMeasuredTopPadding; } private void showFiltersHint() { - if (askingForPermissions || !getMessagesController().dialogFiltersLoaded || !getMessagesController().showFiltersTooltip || filterTabsView == null || filterTabsView.getVisibility() == View.VISIBLE || isPaused || !getUserConfig().filtersLoaded || inPreviewMode) { + if (askingForPermissions || !getMessagesController().dialogFiltersLoaded || !getMessagesController().showFiltersTooltip || filterTabsView == null || !getMessagesController().dialogFilters.isEmpty() || isPaused || !getUserConfig().filtersLoaded || inPreviewMode) { return; } SharedPreferences preferences = MessagesController.getGlobalMainSettings(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java index 8fda2d317..349f7951a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/FilteredSearchView.java @@ -70,6 +70,7 @@ import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.ColoredImageSpan; import org.telegram.ui.Components.CubicBezierInterpolator; import org.telegram.ui.Components.EmbedBottomSheet; +import org.telegram.ui.Components.FlickerLoadingView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.RecyclerListView; import org.telegram.ui.Components.SearchViewPager; @@ -98,8 +99,6 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente String lastMessagesSearchString; String lastSearchFilterQueryString; - int currentAccount = UserConfig.selectedAccount; - FiltersView.MediaFilterData currentSearchFilter; int currentSearchDialogId; long currentSearchMaxDate; @@ -257,7 +256,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente private Delegate delegate; private SearchViewPager.ChatPreviewDelegate chatPreviewDelegate; public final LinearLayoutManager layoutManager; - private final LoadingView loadingView; + private final FlickerLoadingView loadingView; private boolean firstLoading = true; int animationIndex = -1; public int keyboardHeight; @@ -324,27 +323,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente layoutManager = new LinearLayoutManager(context); recyclerListView.setLayoutManager(layoutManager); - addView(loadingView = new LoadingView(context) { - @Override - public int getType() { - if (currentSearchFilter == null) { - return 1; - } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_MEDIA) { - if (!TextUtils.isEmpty(currentSearchString)) { - return 1; - } else { - return 2; - } - } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_FILES) { - return 3; - } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_MUSIC || currentSearchFilter.filterType == FiltersView.FILTER_TYPE_VOICE) { - return 4; - } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_LINKS) { - return 5; - } - return 1; - } - + addView(loadingView = new FlickerLoadingView(context) { @Override public int getColumnsCount() { return columnsCount; @@ -504,6 +483,8 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente final int folderId = uiCallback.getFolderId(); + int currentAccount = UserConfig.selectedAccount; + AndroidUtilities.runOnUIThread(searchRunnable = () -> { TLObject request; @@ -725,7 +706,21 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente } } firstLoading = false; - if (loadingView.getVisibility() == View.VISIBLE && recyclerListView.getChildCount() == 0) { + View progressView = null; + int progressViewPosition = -1; + for (int i = 0; i < n; i++) { + View child = recyclerListView.getChildAt(i); + if (child instanceof FlickerLoadingView) { + progressView = child; + progressViewPosition = recyclerListView.getChildAdapterPosition(child); + } + } + final View finalProgressView = progressView; + if (progressView != null) { + recyclerListView.removeView(progressView); + } + if (loadingView.getVisibility() == View.VISIBLE && recyclerListView.getChildCount() == 0 || progressView != null) { + int finalProgressViewPosition = progressViewPosition; getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -734,6 +729,11 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente AnimatorSet animatorSet = new AnimatorSet(); for (int i = 0; i < n; i++) { View child = recyclerListView.getChildAt(i); + if (finalProgressView != null) { + if (recyclerListView.getChildAdapterPosition(child) < finalProgressViewPosition) { + continue; + } + } child.setAlpha(0); int s = Math.min(recyclerListView.getMeasuredHeight(), Math.max(0, child.getTop())); int delay = (int) ((s / (float) recyclerListView.getMeasuredHeight()) * 100); @@ -751,6 +751,24 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente }); animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); animatorSet.start(); + + if (finalProgressView != null && finalProgressView.getParent() == null) { + recyclerListView.addView(finalProgressView); + RecyclerView.LayoutManager layoutManager = recyclerListView.getLayoutManager(); + if (layoutManager != null) { + layoutManager.ignoreView(finalProgressView); + Animator animator = ObjectAnimator.ofFloat(finalProgressView, ALPHA, finalProgressView.getAlpha(), 0); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finalProgressView.setAlpha(1f); + layoutManager.stopIgnoringView(finalProgressView); + recyclerListView.removeView(finalProgressView); + } + }); + animator.start(); + } + } return true; } }); @@ -759,6 +777,22 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente }); }); }, (filterAndQueryIsSame && !messages.isEmpty()) ? 0 : 350); + + if (currentSearchFilter == null) { + loadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); + } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_MEDIA) { + if (!TextUtils.isEmpty(currentSearchString)) { + loadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); + } else { + loadingView.setViewType(FlickerLoadingView.PHOTOS_TYPE); + } + } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_FILES) { + loadingView.setViewType(FlickerLoadingView.FILES_TYPE); + } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_MUSIC || currentSearchFilter.filterType == FiltersView.FILTER_TYPE_VOICE) { + loadingView.setViewType(FlickerLoadingView.AUDIO_TYPE); + } else if (currentSearchFilter.filterType == FiltersView.FILTER_TYPE_LINKS) { + loadingView.setViewType(FlickerLoadingView.LINKS_TYPE); + } } public void update() { @@ -776,7 +810,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente for (int j = 0; j < messages.size(); j++) { MessageObject messageObject = messages.get(j); long dialogId = messageObject.getDialogId(); - int currentChannelId = dialogId < 0 && ChatObject.isChannel((int) -dialogId, currentAccount) ? (int) -dialogId : 0; + int currentChannelId = dialogId < 0 && ChatObject.isChannel((int) -dialogId, UserConfig.selectedAccount) ? (int) -dialogId : 0; if (currentChannelId == channelId) { for (int i = 0; i < markAsDeletedMessages.size(); i++) { if (messageObject.getId() == markAsDeletedMessages.get(i)) { @@ -955,10 +989,10 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente AndroidUtilities.openDocument(message, parentActivity, parentFragment); } else if (!cell.isLoading()) { MessageObject messageObject = cell.getMessage(); - AccountInstance.getInstance(currentAccount).getFileLoader().loadFile(document, messageObject, 0, 0); + AccountInstance.getInstance(UserConfig.selectedAccount).getFileLoader().loadFile(document, messageObject, 0, 0); cell.updateFileExistIcon(); } else { - AccountInstance.getInstance(currentAccount).getFileLoader().cancelLoadFile(document); + AccountInstance.getInstance(UserConfig.selectedAccount).getFileLoader().cancelLoadFile(document); cell.updateFileExistIcon(); } } @@ -1098,7 +1132,10 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente break; case 2: default: - view = new LoadingCell(mContext, AndroidUtilities.dp(32), AndroidUtilities.dp(54)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + flickerLoadingView.setViewType(FlickerLoadingView.LINKS_TYPE); + flickerLoadingView.setIsSingleCell(true); + view = flickerLoadingView; break; } view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); @@ -1234,7 +1271,14 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente view = new SharedDocumentCell(mContext, SharedDocumentCell.VIEW_TYPE_GLOBAL_SEARCH); break; case 2: - view = new LoadingCell(mContext, AndroidUtilities.dp(32), AndroidUtilities.dp(54)); + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(mContext); + if (currentType == 2 || currentType == 4) { + flickerLoadingView.setViewType(FlickerLoadingView.AUDIO_TYPE); + } else { + flickerLoadingView.setViewType(FlickerLoadingView.FILES_TYPE); + } + flickerLoadingView.setIsSingleCell(true); + view = flickerLoadingView; break; case 3: default: @@ -1363,16 +1407,18 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente EmbedBottomSheet.show(parentActivity, webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height, false); } + int lastAccount; + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.emojiDidLoad); + NotificationCenter.getInstance(lastAccount = UserConfig.selectedAccount).addObserver(this, NotificationCenter.emojiDidLoad); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.emojiDidLoad); + NotificationCenter.getInstance(lastAccount).removeObserver(this, NotificationCenter.emojiDidLoad); } @Override @@ -1439,6 +1485,12 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente case 0: view = new DialogCell(parent.getContext(), true, false); break; + case 3: + FlickerLoadingView flickerLoadingView = new FlickerLoadingView(parent.getContext()); + flickerLoadingView.setIsSingleCell(true); + flickerLoadingView.setViewType(FlickerLoadingView.DIALOG_TYPE); + view = flickerLoadingView; + break; default: case 2: GraySectionCell cell = new GraySectionCell(parent.getContext()); @@ -1477,6 +1529,9 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente @Override public int getItemViewType(int position) { + if (position >= messages.size()) { + return 3; + } return 0; } @@ -1485,7 +1540,7 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente if (messages.isEmpty()) { return 0; } - return messages.size(); + return messages.size() + (endReached ? 0 : 1); } } @@ -1550,169 +1605,6 @@ public class FilteredSearchView extends FrameLayout implements NotificationCente int getFolderId(); } - public static class LoadingView extends View { - - int gradientWidth; - LinearGradient gradient; - Paint paint = new Paint(); - private long lastUpdateTime; - private int totalTranslation; - private Matrix matrix; - RectF rectF = new RectF(); - int color0; - int color1; - - public int getType() { - return 1; - } - - public int getColumnsCount() { - return 2; - } - - public LoadingView(Context context) { - super(context); - matrix = new Matrix(); - } - - @Override - protected void onDraw(Canvas canvas) { - int color0 = Theme.getColor(Theme.key_dialogBackground); - int color1 = Theme.getColor(Theme.key_windowBackgroundGray); - if (this.color1 != color1 || this.color0 != color0) { - this.color0 = color0; - this.color1 = color1; - gradient = new LinearGradient(0, 0, 0, gradientWidth = AndroidUtilities.dp(600), new int[]{color1, color0, color0, color1}, new float[]{0.0f, 0.4f, 0.6f, 1f}, Shader.TileMode.CLAMP); - paint.setShader(gradient); - } - if (getType() == 1) { - int h = 0; - while (h < getMeasuredHeight()) { - int r = AndroidUtilities.dp(25); - canvas.drawCircle(checkRtl(AndroidUtilities.dp(9) + r), h + (AndroidUtilities.dp(78) >> 1), r, paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(20), AndroidUtilities.dp(140), h + AndroidUtilities.dp(28)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(42), AndroidUtilities.dp(260), h + AndroidUtilities.dp(50)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(20), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(28)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - h += AndroidUtilities.dp(78) + 1; - } - } else if (getType() == 2) { - int photoWidth = (getMeasuredWidth() - (AndroidUtilities.dp(2) * (getColumnsCount() - 1))) / getColumnsCount(); - int h = 0; - while (h < getMeasuredHeight()) { - for (int i = 0; i < getColumnsCount(); i++) { - int x = i * (photoWidth + AndroidUtilities.dp(2)); - canvas.drawRect(x, h, x + photoWidth, h + photoWidth, paint); - } - h += photoWidth + AndroidUtilities.dp(2); - } - } else if (getType() == 3) { - int h = 0; - while (h < getMeasuredHeight()) { - rectF.set(AndroidUtilities.dp(12), h + AndroidUtilities.dp(8), AndroidUtilities.dp(52), h + AndroidUtilities.dp(48)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(260), h + AndroidUtilities.dp(42)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - h += AndroidUtilities.dp(56) + 1; - } - } else if (getType() == 4) { - int h = 0; - while (h < getMeasuredHeight()) { - int radius = AndroidUtilities.dp(44) >> 1; - canvas.drawCircle(checkRtl(AndroidUtilities.dp(12) + radius), h + AndroidUtilities.dp(6) + radius, radius, paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(260), h + AndroidUtilities.dp(42)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - h += AndroidUtilities.dp(56) + 1; - } - } else if (getType() == 5) { - int h = 0; - while (h < getMeasuredHeight()) { - rectF.set(AndroidUtilities.dp(10), h + AndroidUtilities.dp(11), AndroidUtilities.dp(62), h + AndroidUtilities.dp(11 + 52)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(12), AndroidUtilities.dp(140), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34), AndroidUtilities.dp(268), h + AndroidUtilities.dp(42)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(AndroidUtilities.dp(68), h + AndroidUtilities.dp(34 + 20), AndroidUtilities.dp(120 + 68), h + AndroidUtilities.dp(42 + 20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - rectF.set(getMeasuredWidth() - AndroidUtilities.dp(50), h + AndroidUtilities.dp(12), getMeasuredWidth() - AndroidUtilities.dp(12), h + AndroidUtilities.dp(20)); - checkRtl(rectF); - canvas.drawRoundRect(rectF, AndroidUtilities.dp(4), AndroidUtilities.dp(4), paint); - - h += AndroidUtilities.dp(80); - } - } - - long newUpdateTime = SystemClock.elapsedRealtime(); - long dt = Math.abs(lastUpdateTime - newUpdateTime); - if (dt > 17) { - dt = 16; - } - lastUpdateTime = newUpdateTime; - totalTranslation += dt * getMeasuredHeight() / 400.0f; - if (totalTranslation >= getMeasuredHeight() * 2) { - totalTranslation = -gradientWidth * 2; - } - matrix.setTranslate(0, totalTranslation); - gradient.setLocalMatrix(matrix); - invalidate(); - } - - private float checkRtl(float x) { - if (LocaleController.isRTL) { - return getMeasuredWidth() - x; - } - return x; - } - - private void checkRtl(RectF rectF) { - if (LocaleController.isRTL) { - rectF.left = getMeasuredWidth() - rectF.left; - rectF.right = getMeasuredWidth() - rectF.right; - } - } - } - private void showFloatingDateView() { AndroidUtilities.cancelRunOnUIThread(hideFloatingDateRunnable); AndroidUtilities.runOnUIThread(hideFloatingDateRunnable, 650); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ForwardsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ForwardsActivity.java deleted file mode 100644 index da62cf241..000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/ForwardsActivity.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 5.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-2018. - */ - -package org.telegram.ui; - -import android.content.Context; -import android.os.Bundle; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChatObject; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.R; -import org.telegram.tgnet.TLObject; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.ActionBar.Theme; -import org.telegram.ui.ActionBar.ThemeDescription; -import org.telegram.ui.Cells.HeaderCell; -import org.telegram.ui.Cells.LoadingCell; -import org.telegram.ui.Cells.ManageChatUserCell; -import org.telegram.ui.Cells.ShadowSectionCell; -import org.telegram.ui.Components.EmptyTextProgressView; -import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.RecyclerListView; - -import java.util.ArrayList; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.SimpleItemAnimator; - -public class ForwardsActivity extends BaseFragment { - - private ListAdapter listViewAdapter; - private EmptyTextProgressView emptyView; - private RecyclerListView listView; - private LinearLayoutManager layoutManager; - - private MessageObject messageObject; - - private ArrayList messages = new ArrayList<>(); - private boolean loading; - private boolean firstLoaded; - - private int headerRow; - private int startRow; - private int endRow; - private int privateRow; - private int sectionRow; - private int loadingRow; - private int rowCount; - - private int nextRate; - private int publicChats; - private boolean endReached; - - public ForwardsActivity(MessageObject message) { - messageObject = message; - } - - private void updateRows() { - sectionRow = -1; - headerRow = -1; - startRow = -1; - endRow = -1; - loadingRow = -1; - privateRow = -1; - - rowCount = 0; - if (firstLoaded) { - headerRow = rowCount++; - if (messageObject.messageOwner.forwards - publicChats > 0) { - privateRow = rowCount++; - } - if (!messages.isEmpty()) { - startRow = rowCount; - rowCount += messages.size(); - endRow = rowCount; - if (!endReached) { - loadingRow = rowCount++; - } - } - sectionRow = rowCount++; - } - if (listViewAdapter != null) { - listViewAdapter.notifyDataSetChanged(); - } - } - - @Override - public boolean onFragmentCreate() { - super.onFragmentCreate(); - loadChats(100); - return true; - } - - @Override - public View createView(Context context) { - actionBar.setBackButtonImage(R.drawable.ic_ab_back); - actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("Shares", R.string.Shares)); - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { - @Override - public void onItemClick(int id) { - if (id == -1) { - finishFragment(); - } - } - }); - - fragmentView = new FrameLayout(context); - fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); - FrameLayout frameLayout = (FrameLayout) fragmentView; - - emptyView = new EmptyTextProgressView(context); - emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); - emptyView.setVisibility(View.GONE); - frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - - listView = new RecyclerListView(context); - listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); - ((SimpleItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); - listView.setAdapter(listViewAdapter = new ListAdapter(context)); - listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); - frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - - listView.setOnItemClickListener((view, position) -> { - if (position >= startRow && position < endRow) { - TLRPC.Message message = messages.get(position - startRow); - int did = (int) MessageObject.getDialogId(message); - Bundle args = new Bundle(); - if (did > 0) { - args.putInt("user_id", did); - } else { - args.putInt("chat_id", -did); - } - args.putInt("message_id", message.id); - if (getMessagesController().checkCanOpenChat(args, this)) { - presentFragment(new ChatActivity(args)); - } - } - }); - - listView.setOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - - } - - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); - int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : Math.abs(layoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; - int totalItemCount = recyclerView.getAdapter().getItemCount(); - - if (visibleItemCount > 0) { - if (!endReached && !loading && !messages.isEmpty() && firstVisibleItem + visibleItemCount >= totalItemCount - 5) { - loadChats(100); - } - } - } - }); - - if (loading) { - emptyView.showProgress(); - } else { - emptyView.showTextView(); - } - updateRows(); - - listView.setEmptyView(emptyView); - - return fragmentView; - } - - private void loadChats(int count) { - if (loading) { - return; - } - loading = true; - if (emptyView != null && messages.isEmpty()) { - emptyView.showProgress(); - } - if (listViewAdapter != null) { - listViewAdapter.notifyDataSetChanged(); - } - TLRPC.TL_stats_getMessagePublicForwards req = new TLRPC.TL_stats_getMessagePublicForwards(); - req.msg_id = messageObject.getId(); - req.limit = count; - req.channel = getMessagesController().getInputChannel((int) -messageObject.getDialogId()); - if (!messages.isEmpty()) { - TLRPC.Message message = messages.get(messages.size()); - req.offset_id = message.id; - req.offset_peer = getMessagesController().getInputPeer((int) MessageObject.getDialogId(message)); - req.offset_rate = nextRate; - } else { - req.offset_peer = new TLRPC.TL_inputPeerEmpty(); - } - int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { - if (error == null) { - TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; - if ((res.flags & 1) != 0) { - nextRate = res.next_rate; - } - if (res.count != 0) { - publicChats = res.count; - } else if (publicChats == 0) { - publicChats = res.messages.size(); - } - endReached = !(res instanceof TLRPC.TL_messages_messagesSlice); - getMessagesController().putChats(res.chats, false); - getMessagesController().putUsers(res.users, false); - messages.addAll(res.messages); - if (emptyView != null) { - emptyView.showTextView(); - } - } - firstLoaded = true; - loading = false; - updateRows(); - })); - getConnectionsManager().bindRequestToGuid(reqId, classGuid); - } - - @Override - public void onResume() { - super.onResume(); - AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); - if (listViewAdapter != null) { - listViewAdapter.notifyDataSetChanged(); - } - } - - private class ListAdapter extends RecyclerListView.SelectionAdapter { - - private Context mContext; - - public ListAdapter(Context context) { - mContext = context; - } - - @Override - public boolean isEnabled(RecyclerView.ViewHolder holder) { - int type = holder.getItemViewType(); - if (type == 0) { - ManageChatUserCell cell = (ManageChatUserCell) holder.itemView; - return cell.getCurrentObject() instanceof TLObject; - } - return false; - } - - @Override - public int getItemCount() { - return rowCount; - } - - @Override - public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view; - switch (viewType) { - case 0: - view = new ManageChatUserCell(mContext, 6, 2, false); - view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - break; - case 1: - view = new ShadowSectionCell(mContext); - break; - case 2: - HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 21, 11, false); - headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); - headerCell.setHeight(43); - view = headerCell; - break; - case 3: - default: - view = new LoadingCell(mContext, AndroidUtilities.dp(40), AndroidUtilities.dp(120)); - break; - } - return new RecyclerListView.Holder(view); - } - - @Override - public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { - switch (holder.getItemViewType()) { - case 0: - ManageChatUserCell userCell = (ManageChatUserCell) holder.itemView; - if (position == privateRow) { - userCell.setData(1, LocaleController.formatPluralString("Shared", messageObject.messageOwner.forwards - publicChats), LocaleController.getString("SharedToPrivateMessagesAndGroups", R.string.SharedToPrivateMessagesAndGroups), startRow != -1); - } else { - TLRPC.Message item = getItem(position); - int did = (int) MessageObject.getDialogId(item); - TLObject object; - String status = null; - if (did > 0) { - object = getMessagesController().getUser(did); - } else { - object = getMessagesController().getChat(-did); - TLRPC.Chat chat = (TLRPC.Chat) object; - if (chat.participants_count != 0) { - if (ChatObject.isChannel(chat) && !chat.megagroup) { - status = LocaleController.formatPluralString("Subscribers", chat.participants_count); - } else { - status = LocaleController.formatPluralString("Members", chat.participants_count); - } - status = String.format("%1$s, %2$s", status, LocaleController.formatDateAudio(item.date, false)); - } - } - if (object != null) { - userCell.setData(object, null, status, position != endRow - 1); - } - } - break; - case 1: - holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); - break; - case 2: - HeaderCell headerCell = (HeaderCell) holder.itemView; - headerCell.setText(LocaleController.formatPluralString("Shares", messageObject.messageOwner.forwards)); - break; - } - } - - @Override - public void onViewRecycled(RecyclerView.ViewHolder holder) { - if (holder.itemView instanceof ManageChatUserCell) { - ((ManageChatUserCell) holder.itemView).recycle(); - } - } - - @Override - public int getItemViewType(int position) { - if (position == sectionRow) { - return 1; - } else if (position == headerRow) { - return 2; - } else if (position == loadingRow) { - return 3; - } - return 0; - } - - public TLRPC.Message getItem(int position) { - if (position >= startRow && position < endRow) { - return messages.get(position - startRow); - } - return null; - } - } - - @Override - public ArrayList getThemeDescriptions() { - ArrayList themeDescriptions = new ArrayList<>(); - - ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - if (child instanceof ManageChatUserCell) { - ((ManageChatUserCell) child).update(0); - } - } - } - }; - - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); - themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray)); - - themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_actionBarDefault)); - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault)); - themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_ITEMSCOLOR, null, null, null, null, Theme.key_actionBarDefaultIcon)); - themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_TITLECOLOR, null, null, null, null, Theme.key_actionBarDefaultTitle)); - themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SELECTORCOLOR, null, null, null, null, Theme.key_actionBarDefaultSelector)); - - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); - - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); - - themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); - - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); - - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteGrayText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusOnlineColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteBlueText)); - themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, null, Theme.avatarDrawables, null, Theme.key_avatar_text)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundOrange)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundViolet)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundGreen)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundCyan)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundBlue)); - themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); - - return themeDescriptions; - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 9328ef12a..466da0aa5 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -106,6 +106,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private boolean doneButtonVisible; private boolean ignoreScrollEvent; + private int measuredContainerHeight; private int containerHeight; private int chatId; @@ -128,6 +129,9 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private int fieldY; + private AnimatorSet currentAnimation; + int maxSize; + private final static int done_button = 1; public interface GroupCreateActivityDelegate { @@ -144,11 +148,11 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private class SpansContainer extends ViewGroup { - private AnimatorSet currentAnimation; private boolean animationStarted; private ArrayList animators = new ArrayList<>(); private View addingSpan; private View removingSpan; + private int animationIndex = -1; public SpansContainer(Context context) { super(context); @@ -223,6 +227,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen if (containerHeight != resultHeight) { animators.add(ObjectAnimator.ofInt(GroupCreateActivity.this, "containerHeight", resultHeight)); } + measuredContainerHeight = Math.max(containerHeight, resultHeight); if (editText.getTranslationX() != fieldX) { animators.add(ObjectAnimator.ofFloat(editText, "translationX", fieldX)); } @@ -231,10 +236,19 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen } editText.setAllowDrawCursor(false); currentAnimation.playTogether(animators); + currentAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + NotificationCenter.getInstance(currentAccount).onAnimationFinish(animationIndex); + requestLayout(); + super.onAnimationEnd(animation); + } + }); + animationIndex = NotificationCenter.getInstance(currentAccount).setAnimationInProgress(animationIndex, null); currentAnimation.start(); animationStarted = true; } else { - containerHeight = currentHeight; + measuredContainerHeight = containerHeight = currentHeight; editText.setTranslationX(fieldX); editText.setTranslationY(fieldY); } @@ -243,7 +257,8 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen editText.bringPointIntoView(editText.getSelectionStart()); } } - setMeasuredDimension(width, containerHeight); + setMeasuredDimension(width, measuredContainerHeight); + listView.setTranslationY(0); } @Override @@ -448,7 +463,6 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(width, height); - int maxSize; if (AndroidUtilities.isTablet() || height > width) { maxSize = AndroidUtilities.dp(144); } else { @@ -479,11 +493,22 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen @Override protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - boolean result = super.drawChild(canvas, child, drawingTime); if (child == listView || child == emptyView) { - parentLayout.drawHeaderShadow(canvas, scrollView.getMeasuredHeight()); + canvas.save(); + canvas.clipRect(child.getLeft(), Math.min(maxSize, measuredContainerHeight + containerHeight - measuredContainerHeight), child.getRight(), child.getBottom()); + boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + parentLayout.drawHeaderShadow(canvas, Math.min(maxSize, measuredContainerHeight + containerHeight - measuredContainerHeight)); + return result; + } else if (child == scrollView) { + canvas.save(); + canvas.clipRect(child.getLeft(), child.getTop(), child.getRight(), Math.min(maxSize, measuredContainerHeight + containerHeight - measuredContainerHeight)); + boolean result = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return result; + } else { + return super.drawChild(canvas, child, drawingTime); } - return result; } }; ViewGroup frameLayout = (ViewGroup) fragmentView; @@ -501,6 +526,8 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen return super.requestChildRectangleOnScreen(child, rectangle, immediate); } }; + scrollView.setClipChildren(false); + frameLayout.setClipChildren(false); scrollView.setVerticalScrollBarEnabled(false); AndroidUtilities.setScrollViewEdgeEffectColor(scrollView, Theme.getColor(Theme.key_windowBackgroundWhite)); frameLayout.addView(scrollView); @@ -741,6 +768,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { + editText.hideActionMode(); AndroidUtilities.hideKeyboard(editText); } } @@ -839,10 +867,13 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen @Keep public void setContainerHeight(int value) { + int dy = containerHeight - value; containerHeight = value; - if (spansContainer != null) { - spansContainer.requestLayout(); - } + int measuredH = Math.min(maxSize, measuredContainerHeight); + int currentH = Math.min(maxSize, containerHeight); + scrollView.scrollTo(0, Math.max(0, scrollView.getScrollY() - dy)); + listView.setTranslationY(currentH - measuredH); + fragmentView.invalidate(); } @Keep diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index 335eaa25f..758447078 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -48,7 +48,6 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; -import org.telegram.messenger.SharedConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java index fb329c723..d4be1d576 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupStickersActivity.java @@ -502,7 +502,7 @@ public class GroupStickersActivity extends BaseFragment implements NotificationC info.flags = info.flags &~ 256; } MessagesStorage.getInstance(currentAccount).updateChatInfo(info, false); - NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, true, null); + NotificationCenter.getInstance(currentAccount).postNotificationName(NotificationCenter.chatInfoDidLoad, info, 0, true); finishFragment(); } else { Toast.makeText(getParentActivity(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text, Toast.LENGTH_SHORT).show(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 1bc65e66e..34a6d0ee2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -217,6 +217,7 @@ public class LocationActivity extends BaseFragment implements NotificationCenter public final static int LOCATION_TYPE_SEND_WITH_LIVE = 1; public final static int LOCATION_TYPE_GROUP = 4; public final static int LOCATION_TYPE_GROUP_VIEW = 5; + public final static int LOCATION_TYPE_LIVE_VIEW = 6; private Runnable markAsReadRunnable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index d0349b818..60b5f0bba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -1232,7 +1232,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No } if (!AndroidUtilities.isTablet()) { - frameLayout.addView(fragmentContextView = new FragmentContextView(context, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, 8, 0, 0)); + frameLayout.addView(fragmentContextView = new FragmentContextView(context, this, false), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 38, Gravity.TOP | Gravity.LEFT, 0, 8, 0, 0)); } frameLayout.addView(actionBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java new file mode 100644 index 000000000..ed7ad469f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessageStatisticActivity.java @@ -0,0 +1,982 @@ +/* + * This is the source code of Telegram for Android v. 5.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-2018. + */ + +package org.telegram.ui; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.DownloadController; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.ImageLocation; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.LruCache; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ActionBar.ThemeDescription; +import org.telegram.ui.Cells.DialogCell; +import org.telegram.ui.Cells.EmptyCell; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.LoadingCell; +import org.telegram.ui.Cells.ManageChatUserCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Charts.BaseChartView; +import org.telegram.ui.Charts.data.ChartData; +import org.telegram.ui.Charts.data.StackLinearChartData; +import org.telegram.ui.Charts.view_data.ChartHeaderView; +import org.telegram.ui.Components.ChatAvatarContainer; +import org.telegram.ui.Components.CombinedDrawable; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RLottieImageView; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.ArrayList; + +import androidx.collection.ArraySet; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + +public class MessageStatisticActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private TLRPC.ChatFull chat; + private final int chatId; + private final int messageId; + private ListAdapter listViewAdapter; + private EmptyTextProgressView emptyView; + private RecyclerListView listView; + private LinearLayoutManager layoutManager; + + private MessageObject messageObject; + private StatisticActivity.ChartViewData interactionsViewData; + private LruCache childDataCache = new LruCache<>(15); + private StatisticActivity.ZoomCancelable lastCancelable; + + private ArrayList messages = new ArrayList<>(); + private boolean statsLoaded; + private boolean loading; + private boolean firstLoaded; + + private int headerRow; + private int startRow; + private int endRow; + private int loadingRow; + private int interactionsChartRow; + private int overviewRow; + private int overviewHeaderRow; + private int emptyRow; + private int rowCount; + + ArraySet shadowDivideCells = new ArraySet<>(); + + private RLottieImageView imageView; + private LinearLayout progressLayout; + + private int nextRate; + private int publicChats; + private boolean endReached; + + ImageReceiver thumbImage; + boolean drawPlay; + + private final Runnable showProgressbar = new Runnable() { + @Override + public void run() { + progressLayout.animate().alpha(1f).setDuration(230); + } + }; + private FrameLayout listContainer; + private ChatAvatarContainer avatarContainer; + private BaseChartView.SharedUiComponents sharedUi; + + public MessageStatisticActivity(MessageObject message) { + messageObject = message; + + if (messageObject.messageOwner.fwd_from == null) { + chatId = messageObject.getChatId(); + messageId = messageObject.getId(); + } else { + chatId = -messageObject.getFromChatId(); + messageId = messageObject.messageOwner.fwd_msg_id; + } + this.chat = getMessagesController().getChatFull(chatId); + } + + private void updateRows() { + shadowDivideCells.clear(); + headerRow = -1; + startRow = -1; + endRow = -1; + loadingRow = -1; + interactionsChartRow = -1; + overviewHeaderRow = -1; + overviewRow = -1; + + rowCount = 0; + if (firstLoaded && statsLoaded) { + AndroidUtilities.cancelRunOnUIThread(showProgressbar); + if (listContainer.getVisibility() == View.GONE) { + progressLayout.animate().alpha(0).setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + progressLayout.setVisibility(View.GONE); + } + }); + listContainer.setVisibility(View.VISIBLE); + listContainer.setAlpha(0f); + listContainer.animate().alpha(1f).start(); + } + + overviewHeaderRow = rowCount++; + overviewRow = rowCount++; + shadowDivideCells.add(rowCount++); + if (interactionsViewData != null) { + interactionsChartRow = rowCount++; + shadowDivideCells.add(rowCount++); + } + + if (!messages.isEmpty()) { + headerRow = rowCount++; + startRow = rowCount; + rowCount += messages.size(); + endRow = rowCount; + emptyRow = rowCount++; + shadowDivideCells.add(rowCount++); + + if (!endReached) { + loadingRow = rowCount++; + } + } + } + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + if (chat != null) { + loadStat(); + loadChats(100); + } else { + MessagesController.getInstance(currentAccount).loadFullChat(chatId, classGuid, true); + } + NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.chatInfoDidLoad); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.chatInfoDidLoad); + } + + @Override + public void didReceivedNotification(int id, int account, Object... args) { + if (id == NotificationCenter.chatInfoDidLoad) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chat == null && chatFull.id == chatId) { + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); + if (chatLocal != null) { + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } + chat = chatFull; + loadStat(); + loadChats(100); + updateMenu(); + } + } + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + + fragmentView = new FrameLayout(context); + fragmentView.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundGray)); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + emptyView = new EmptyTextProgressView(context); + emptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + emptyView.setVisibility(View.GONE); + + progressLayout = new LinearLayout(context); + progressLayout.setOrientation(LinearLayout.VERTICAL); + + imageView = new RLottieImageView(context); + imageView.setAutoRepeat(true); + imageView.setAnimation(R.raw.statistic_preload, 120, 120); + imageView.playAnimation(); + + TextView loadingTitle = new TextView(context); + loadingTitle.setTextSize(20); + loadingTitle.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + loadingTitle.setTextColor(Theme.getColor(Theme.key_player_actionBarTitle)); + loadingTitle.setTag(Theme.key_player_actionBarTitle); + loadingTitle.setText(LocaleController.getString("LoadingStats", R.string.LoadingStats)); + loadingTitle.setGravity(Gravity.CENTER_HORIZONTAL); + + TextView loadingSubtitle = new TextView(context); + loadingSubtitle.setTextSize(15); + loadingSubtitle.setTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + loadingSubtitle.setTag(Theme.key_player_actionBarSubtitle); + loadingSubtitle.setText(LocaleController.getString("LoadingStatsDescription", R.string.LoadingStatsDescription)); + loadingSubtitle.setGravity(Gravity.CENTER_HORIZONTAL); + + progressLayout.addView(imageView, LayoutHelper.createLinear(120, 120, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 20)); + progressLayout.addView(loadingTitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 0, 0, 10)); + progressLayout.addView(loadingSubtitle, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); + progressLayout.setAlpha(0); + + frameLayout.addView(progressLayout, LayoutHelper.createFrame(240, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, 30)); + + listView = new RecyclerListView(context); + listView.setLayoutManager(layoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)); + ((SimpleItemAnimator) listView.getItemAnimator()).setSupportsChangeAnimations(false); + listView.setAdapter(listViewAdapter = new ListAdapter(context)); + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? RecyclerListView.SCROLLBAR_POSITION_LEFT : RecyclerListView.SCROLLBAR_POSITION_RIGHT); + + listView.setOnItemClickListener((view, position) -> { + if (position >= startRow && position < endRow) { + TLRPC.Message message = messages.get(position - startRow); + int did = (int) MessageObject.getDialogId(message); + Bundle args = new Bundle(); + if (did > 0) { + args.putInt("user_id", did); + } else { + args.putInt("chat_id", -did); + } + args.putInt("message_id", message.id); + args.putBoolean("need_remove_previous_same_chat_activity", false); + if (getMessagesController().checkCanOpenChat(args, this)) { + presentFragment(new ChatActivity(args)); + } + } + }); + + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); + int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : Math.abs(layoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; + int totalItemCount = recyclerView.getAdapter().getItemCount(); + + if (visibleItemCount > 0) { + if (!endReached && !loading && !messages.isEmpty() && firstVisibleItem + visibleItemCount >= totalItemCount - 5 && statsLoaded) { + loadChats(100); + } + } + } + }); + emptyView.showTextView(); + + listContainer = new FrameLayout(context); + listContainer.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listContainer.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listContainer.setVisibility(View.GONE); + frameLayout.addView(listContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + AndroidUtilities.runOnUIThread(showProgressbar, 300); + + updateRows(); + listView.setEmptyView(emptyView); + + avatarContainer = new ChatAvatarContainer(context, null, false) { + @Override + protected void dispatchDraw(Canvas canvas) { + super.dispatchDraw(canvas); + thumbImage.setImageCoords(avatarContainer.getSubtitleTextView().getX(), avatarContainer.getSubtitleTextView().getY(), AndroidUtilities.dp(18), AndroidUtilities.dp(18)); + thumbImage.draw(canvas); + if (drawPlay) { + int x = (int) (thumbImage.getCenterX() - Theme.dialogs_playDrawable.getIntrinsicWidth() / 2); + int y = (int) (thumbImage.getCenterY() - Theme.dialogs_playDrawable.getIntrinsicHeight() / 2); + Theme.dialogs_playDrawable.setBounds(x, y, x + Theme.dialogs_playDrawable.getIntrinsicWidth(), y + Theme.dialogs_playDrawable.getIntrinsicHeight()); + Theme.dialogs_playDrawable.draw(canvas); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + thumbImage.onAttachedToWindow(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + thumbImage.onDetachedFromWindow(); + } + }; + + thumbImage = new ImageReceiver(); + thumbImage.setParentView(avatarContainer); + thumbImage.setRoundRadius(AndroidUtilities.dp(2)); + actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, !inPreviewMode ? 56 : 0, 0, 40, 0)); + + TLRPC.Chat chatLocal = getMessagesController().getChat(chatId); + if (chatLocal != null) { + avatarContainer.setChatAvatar(chatLocal); + avatarContainer.setTitle(chatLocal.title); + } + + boolean hasThumb = false; + + if (!messageObject.needDrawBluredPreview() && (messageObject.isPhoto() || messageObject.isNewGif() || messageObject.isVideo())) { + String type = messageObject.isWebpage() ? messageObject.messageOwner.media.webpage.type : null; + if (!("app".equals(type) || "profile".equals(type) || "article".equals(type))) { + TLRPC.PhotoSize smallThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 40); + TLRPC.PhotoSize bigThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + if (smallThumb == bigThumb) { + bigThumb = null; + } + if (smallThumb != null) { + hasThumb = true; + drawPlay = messageObject.isVideo(); + String fileName = FileLoader.getAttachFileName(bigThumb); + if (messageObject.mediaExists || DownloadController.getInstance(currentAccount).canDownloadMedia(messageObject) || FileLoader.getInstance(currentAccount).isLoadingFile(fileName)) { + int size; + if (messageObject.type == MessageObject.TYPE_PHOTO) { + size = bigThumb != null ? bigThumb.size : 0; + } else { + size = 0; + } + thumbImage.setImage(ImageLocation.getForObject(bigThumb, messageObject.photoThumbsObject), "20_20", ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", size, null, messageObject, 0); + } else { + thumbImage.setImage(null, null, ImageLocation.getForObject(smallThumb, messageObject.photoThumbsObject), "20_20", null, messageObject, 0); + } + } + } + } + + CharSequence message; + if (!TextUtils.isEmpty(messageObject.caption)) { + message = messageObject.caption; + } else if (!TextUtils.isEmpty(messageObject.messageOwner.message)) { + message = messageObject.messageText; + if (message.length() > 150) { + message = message.subSequence(0, 150); + } + message = Emoji.replaceEmoji(message, avatarContainer.getSubtitleTextView().getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(17), false); + } else { + message = messageObject.messageText; + } + + if (hasThumb) { + SpannableStringBuilder builder = new SpannableStringBuilder(message); + builder.insert(0, " "); + builder.setSpan(new DialogCell.FixedWidthSpan(AndroidUtilities.dp(18 + 6)), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + avatarContainer.setSubtitle(builder); + } else { + avatarContainer.setSubtitle(messageObject.messageText); + } + actionBar.setBackButtonDrawable(new BackDrawable(false)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(final int id) { + if (id == -1) { + finishFragment(); + } else if (id == 1) { + Bundle args = new Bundle(); + if (messageObject.messageOwner.fwd_from == null) { + args.putInt("chat_id", messageObject.getChatId()); + } else { + args.putInt("chat_id", -messageObject.getFromChatId()); + } + presentFragment(new StatisticActivity(args)); + } + } + }); + + avatarContainer.setTitleColors(Theme.getColor(Theme.key_player_actionBarTitle), Theme.getColor(Theme.key_player_actionBarSubtitle)); + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + actionBar.setItemsColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2), false); + actionBar.setItemsBackgroundColor(Theme.getColor(Theme.key_actionBarActionModeDefaultSelector), false); + actionBar.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + + avatarContainer.setOnClickListener(view -> { + if (getParentLayout().fragmentsStack.size() > 1) { + BaseFragment previousFragemnt = getParentLayout().fragmentsStack.get(getParentLayout().fragmentsStack.size() - 2); + if (previousFragemnt instanceof ChatActivity && ((ChatActivity) previousFragemnt).getCurrentChat().id == chatId) { + finishFragment(); + return; + } + } + Bundle args = new Bundle(); + args.putInt("chat_id", chatId); + args.putInt("message_id", messageId); + args.putBoolean("need_remove_previous_same_chat_activity", false); + ChatActivity a = new ChatActivity(args); + presentFragment(a); + }); + + updateMenu(); + return fragmentView; + } + + private void updateMenu() { + if (chat != null && chat.can_view_stats) { + ActionBarMenu menu = actionBar.createMenu(); + menu.clearItems(); + ActionBarMenuItem headerItem = menu.addItem(0, R.drawable.ic_ab_other); + headerItem.addSubItem(1, R.drawable.msg_stats, LocaleController.getString("ViewChannelStats", R.string.ViewChannelStats)); + } + } + + private void loadChats(int count) { + if (loading) { + return; + } + loading = true; + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + TLRPC.TL_stats_getMessagePublicForwards req = new TLRPC.TL_stats_getMessagePublicForwards(); + req.limit = count; + if (messageObject.messageOwner.fwd_from != null) { + req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; + req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + } else { + req.msg_id = messageObject.getId(); + req.channel = getMessagesController().getInputChannel((int) -messageObject.getDialogId()); + } + if (!messages.isEmpty()) { + TLRPC.Message message = messages.get(messages.size() - 1); + req.offset_id = message.id; + req.offset_peer = getMessagesController().getInputPeer((int) MessageObject.getDialogId(message)); + req.offset_rate = nextRate; + } else { + req.offset_peer = new TLRPC.TL_inputPeerEmpty(); + } + int reqId = getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if ((res.flags & 1) != 0) { + nextRate = res.next_rate; + } + if (res.count != 0) { + publicChats = res.count; + } else if (publicChats == 0) { + publicChats = res.messages.size(); + } + endReached = !(res instanceof TLRPC.TL_messages_messagesSlice); + getMessagesController().putChats(res.chats, false); + getMessagesController().putUsers(res.users, false); + messages.addAll(res.messages); + if (emptyView != null) { + emptyView.showTextView(); + } + } + firstLoaded = true; + loading = false; + updateRows(); + }), null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + getConnectionsManager().bindRequestToGuid(reqId, classGuid); + } + + private void loadStat() { + TLRPC.TL_stats_getMessageStats req = new TLRPC.TL_stats_getMessageStats(); + if (messageObject.messageOwner.fwd_from != null) { + req.msg_id = messageObject.messageOwner.fwd_from.saved_from_msg_id; + req.channel = getMessagesController().getInputChannel(-messageObject.getFromChatId()); + } else { + req.msg_id = messageObject.getId(); + req.channel = getMessagesController().getInputChannel((int) -messageObject.getDialogId()); + } + getConnectionsManager().sendRequest(req, (response, error) -> AndroidUtilities.runOnUIThread(() -> { + statsLoaded = true; + if (error != null) { + updateRows(); + return; + } + TLRPC.TL_stats_messageStats res = (TLRPC.TL_stats_messageStats) response; + interactionsViewData = StatisticActivity.createViewData(res.views_graph, LocaleController.getString("InteractionsChartTitle", R.string.InteractionsChartTitle), 1, false); + if (interactionsViewData != null && interactionsViewData.chartData.x.length <= 5) { + statsLoaded = false; + TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); + request.token = interactionsViewData.zoomToken; + request.x = interactionsViewData.chartData.x[interactionsViewData.chartData.x.length - 1]; + request.flags |= 1; + + final String cacheKey = interactionsViewData.zoomToken + "_" + request.x; + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response1, error1) -> { + ChartData childData = null; + if (response1 instanceof TLRPC.TL_statsGraph) { + String json = ((TLRPC.TL_statsGraph) response1).json.data; + try { + childData = StatisticActivity.createChartData(new JSONObject(json), 1, false); + } catch (JSONException e) { + e.printStackTrace(); + } + } else if (response1 instanceof TLRPC.TL_statsGraphError) { + Toast.makeText(getParentActivity(), ((TLRPC.TL_statsGraphError) response1).error, Toast.LENGTH_LONG).show(); + } + + ChartData finalChildData = childData; + AndroidUtilities.runOnUIThread(() -> { + statsLoaded = true; + if (error1 != null || finalChildData == null) { + updateRows(); + return; + } + childDataCache.put(cacheKey, finalChildData); + interactionsViewData.childChartData = finalChildData; + interactionsViewData.activeZoom = request.x; + updateRows(); + }); + }, null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } else { + updateRows(); + } + }), null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + + private class ListAdapter extends RecyclerListView.SelectionAdapter { + + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean isEnabled(RecyclerView.ViewHolder holder) { + int type = holder.getItemViewType(); + if (type == 0) { + ManageChatUserCell cell = (ManageChatUserCell) holder.itemView; + return cell.getCurrentObject() instanceof TLObject; + } + return false; + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) { + case 0: + view = new ManageChatUserCell(mContext, 6, 2, false); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 1: + view = new ShadowSectionCell(mContext); + break; + case 2: + HeaderCell headerCell = new HeaderCell(mContext, Theme.key_windowBackgroundWhiteBlueHeader, 16, 11, false); + headerCell.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + headerCell.setHeight(43); + view = headerCell; + break; + case 4: + view = new StatisticActivity.BaseChartCell(mContext, 1, sharedUi = new BaseChartView.SharedUiComponents()) { + + @Override + public void onZoomed() { + if (data.activeZoom > 0) { + return; + } + performClick(); + if (!chartView.legendSignatureView.canGoZoom) { + return; + } + final long x = chartView.getSelectedDate(); + if (chartType == 4) { + data.childChartData = new StackLinearChartData(data.chartData, x); + zoomChart(false); + return; + } + + if (data.zoomToken == null) { + return; + } + + zoomCanceled(); + final String cacheKey = data.zoomToken + "_" + x; + ChartData dataFromCache = childDataCache.get(cacheKey); + if (dataFromCache != null) { + data.childChartData = dataFromCache; + zoomChart(false); + return; + } + + TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); + request.token = data.zoomToken; + if (x != 0) { + request.x = x; + request.flags |= 1; + } + StatisticActivity.ZoomCancelable finalCancelabel; + lastCancelable = finalCancelabel = new StatisticActivity.ZoomCancelable(); + finalCancelabel.adapterPosition = listView.getChildAdapterPosition(this); + + chartView.legendSignatureView.showProgress(true, false); + + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + ChartData childData = null; + if (response instanceof TLRPC.TL_statsGraph) { + String json = ((TLRPC.TL_statsGraph) response).json.data; + try { + childData = StatisticActivity.createChartData(new JSONObject(json), data.graphType, false); + } catch (JSONException e) { + e.printStackTrace(); + } + } else if (response instanceof TLRPC.TL_statsGraphError) { + Toast.makeText(getContext(), ((TLRPC.TL_statsGraphError) response).error, Toast.LENGTH_LONG).show(); + } + + ChartData finalChildData = childData; + AndroidUtilities.runOnUIThread(() -> { + if (finalChildData != null) { + childDataCache.put(cacheKey, finalChildData); + } + if (finalChildData != null && !finalCancelabel.canceled && finalCancelabel.adapterPosition >= 0) { + View view = layoutManager.findViewByPosition(finalCancelabel.adapterPosition); + if (view instanceof StatisticActivity.BaseChartCell) { + data.childChartData = finalChildData; + ((StatisticActivity.BaseChartCell) view).chartView.legendSignatureView.showProgress(false, false); + ((StatisticActivity.BaseChartCell) view).zoomChart(false); + } + } + zoomCanceled(); + }); + }, null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } + + @Override + public void zoomCanceled() { + if (lastCancelable != null) { + lastCancelable.canceled = true; + } + int n = listView.getChildCount(); + for (int i = 0; i < n; i++) { + View child = listView.getChildAt(i); + if (child instanceof StatisticActivity.BaseChartCell) { + ((StatisticActivity.BaseChartCell) child).chartView.legendSignatureView.showProgress(false, true); + } + } + } + + @Override + void loadData(StatisticActivity.ChartViewData viewData) { + // viewData.load(currentAccount, classGuid, ); + } + }; + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 5: + view = new OverviewCell(mContext); + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 6: + view = new EmptyCell(mContext, 16); + view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 16)); + view.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + break; + case 3: + default: + view = new LoadingCell(mContext, AndroidUtilities.dp(40), AndroidUtilities.dp(120)); + break; + } + return new RecyclerListView.Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + switch (holder.getItemViewType()) { + case 0: + ManageChatUserCell userCell = (ManageChatUserCell) holder.itemView; + TLRPC.Message item = getItem(position); + int did = (int) MessageObject.getDialogId(item); + TLObject object; + String status = null; + if (did > 0) { + object = getMessagesController().getUser(did); + } else { + object = getMessagesController().getChat(-did); + TLRPC.Chat chat = (TLRPC.Chat) object; + if (chat.participants_count != 0) { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + status = LocaleController.formatPluralString("Subscribers", chat.participants_count); + } else { + status = LocaleController.formatPluralString("Members", chat.participants_count); + } + status = String.format("%1$s, %2$s", status, LocaleController.formatPluralString("Views", item.views)); + } + } + if (object != null) { + userCell.setData(object, null, status, position != endRow - 1); + } + break; + case 1: + holder.itemView.setBackgroundDrawable(Theme.getThemedDrawable(mContext, R.drawable.greydivider_bottom, Theme.key_windowBackgroundGrayShadow)); + break; + case 2: + HeaderCell headerCell = (HeaderCell) holder.itemView; + if (position == overviewHeaderRow) { + headerCell.setText(LocaleController.formatString("StatisticOverview", R.string.StatisticOverview)); + } else { + headerCell.setText(LocaleController.formatPluralString("PublicSharesCount", publicChats)); + } + break; + case 4: + StatisticActivity.BaseChartCell chartCell = (StatisticActivity.BaseChartCell) holder.itemView; + chartCell.updateData(interactionsViewData, false); + chartCell.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + break; + case 5: + OverviewCell overviewCell = (OverviewCell) holder.itemView; + overviewCell.setData(); + break; + } + } + + @Override + public void onViewRecycled(RecyclerView.ViewHolder holder) { + if (holder.itemView instanceof ManageChatUserCell) { + ((ManageChatUserCell) holder.itemView).recycle(); + } + } + + @Override + public int getItemViewType(int position) { + if (shadowDivideCells.contains(position)) { + return 1; + } else if (position == headerRow || position == overviewHeaderRow) { + return 2; + } else if (position == loadingRow) { + return 3; + } else if (position == interactionsChartRow) { + return 4; + } else if (position == overviewRow) { + return 5; + } else if (position == emptyRow) { + return 6; + } + return 0; + } + + public TLRPC.Message getItem(int position) { + if (position >= startRow && position < endRow) { + return messages.get(position - startRow); + } + return null; + } + } + + public class OverviewCell extends LinearLayout { + + TextView[] primary = new TextView[3]; + TextView[] title = new TextView[3]; + View[] cell = new View[3]; + + public OverviewCell(Context context) { + super(context); + setOrientation(VERTICAL); + setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(16)); + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(HORIZONTAL); + + for (int j = 0; j < 3; j++) { + LinearLayout contentCell = new LinearLayout(context); + cell[j] = contentCell; + contentCell.setOrientation(VERTICAL); + + primary[j] = new TextView(context); + title[j] = new TextView(context); + + primary[j].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + primary[j].setTextSize(17); + title[j].setTextSize(13); + + contentCell.addView(primary[j]); + contentCell.addView(title[j]); + linearLayout.addView(contentCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 1f)); + } + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + public void setData() { + primary[0].setText(AndroidUtilities.formatWholeNumber(messageObject.messageOwner.views, 0)); + title[0].setText(LocaleController.getString("StatisticViews", R.string.StatisticViews)); + + if (publicChats > 0) { + cell[1].setVisibility(View.VISIBLE); + primary[1].setText(AndroidUtilities.formatWholeNumber(publicChats, 0)); + title[1].setText(LocaleController.formatString("PublicShares", R.string.PublicShares)); + } else { + cell[1].setVisibility(View.GONE); + } + + int privateChats = messageObject.messageOwner.forwards - publicChats; + if (privateChats > 0) { + cell[2].setVisibility(View.VISIBLE); + primary[2].setText(AndroidUtilities.formatWholeNumber(privateChats, 0)); + title[2].setText(LocaleController.formatString("PrivateShares", R.string.PrivateShares)); + } else { + cell[2].setVisibility(View.GONE); + } + + updateColors(); + } + + private void updateColors() { + for (int i = 0; i < 3; i++) { + primary[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteBlackText)); + title[i].setTextColor(Theme.getColor(Theme.key_windowBackgroundWhiteGrayText2)); + } + } + } + + @Override + public ArrayList getThemeDescriptions() { + ArrayList themeDescriptions = new ArrayList<>(); + + ThemeDescription.ThemeDescriptionDelegate cellDelegate = () -> { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + recolorRecyclerItem(listView.getChildAt(a)); + } + count = listView.getHiddenChildCount(); + for (int a = 0; a < count; a++) { + recolorRecyclerItem(listView.getHiddenChildAt(a)); + } + count = listView.getCachedChildCount(); + for (int a = 0; a < count; a++) { + recolorRecyclerItem(listView.getCachedChildAt(a)); + } + count = listView.getAttachedScrapChildCount(); + for (int a = 0; a < count; a++) { + recolorRecyclerItem(listView.getAttachedScrapChildAt(a)); + } + listView.getRecycledViewPool().clear(); + } + if (sharedUi != null) { + sharedUi.invalidate(); + } + + avatarContainer.getSubtitleTextView().setLinkTextColor(Theme.getColor(Theme.key_player_actionBarSubtitle)); + }; + + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{HeaderCell.class, ManageChatUserCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); + themeDescriptions.add(new ThemeDescription(fragmentView, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundGray)); + themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_BACKGROUND, null, null, null, null, Theme.key_windowBackgroundWhite)); + themeDescriptions.add(new ThemeDescription(avatarContainer != null ? avatarContainer.getTitleTextView() : null, ThemeDescription.FLAG_TEXTCOLOR, null, null, null, null, Theme.key_player_actionBarTitle)); + themeDescriptions.add(new ThemeDescription(avatarContainer != null ? avatarContainer.getSubtitleTextView() : null, ThemeDescription.FLAG_TEXTCOLOR | ThemeDescription.FLAG_CHECKTAG, null, null, null, null, Theme.key_player_actionBarSubtitle, null)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_statisticChartLineEmpty)); + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_LISTGLOWCOLOR, null, null, null, null, Theme.key_actionBarDefault)); + + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_SELECTOR, null, null, null, null, Theme.key_listSelector)); + + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{View.class}, Theme.dividerPaint, null, null, Theme.key_divider)); + + themeDescriptions.add(new ThemeDescription(listView, ThemeDescription.FLAG_BACKGROUNDFILTER, new Class[]{ShadowSectionCell.class}, null, null, null, Theme.key_windowBackgroundGrayShadow)); + + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{HeaderCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteBlueHeader)); + + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"nameTextView"}, null, null, null, Theme.key_windowBackgroundWhiteBlackText)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteGrayText)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, new String[]{"statusOnlineColor"}, null, null, cellDelegate, Theme.key_windowBackgroundWhiteBlueText)); + themeDescriptions.add(new ThemeDescription(listView, 0, new Class[]{ManageChatUserCell.class}, null, Theme.avatarDrawables, null, Theme.key_avatar_text)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundRed)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundOrange)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundViolet)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundGreen)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundCyan)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundBlue)); + themeDescriptions.add(new ThemeDescription(null, 0, null, null, null, cellDelegate, Theme.key_avatar_backgroundPink)); + + themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUBACKGROUND, null, null, null, null, Theme.key_actionBarDefaultSubmenuBackground)); + themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM, null, null, null, null, Theme.key_actionBarDefaultSubmenuItem)); + themeDescriptions.add(new ThemeDescription(actionBar, ThemeDescription.FLAG_AB_SUBMENUITEM | ThemeDescription.FLAG_IMAGECOLOR, null, null, null, null, Theme.key_actionBarDefaultSubmenuItemIcon)); + + StatisticActivity.putColorFromData(interactionsViewData, themeDescriptions, cellDelegate); + return themeDescriptions; + } + + private void recolorRecyclerItem(View child) { + if (child instanceof ManageChatUserCell) { + ((ManageChatUserCell) child).update(0); + } else if (child instanceof StatisticActivity.BaseChartCell) { + ((StatisticActivity.BaseChartCell) child).recolor(); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } else if (child instanceof ShadowSectionCell) { + Drawable shadowDrawable = Theme.getThemedDrawable(ApplicationLoader.applicationContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); + Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); + CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); + combinedDrawable.setFullsize(true); + child.setBackground(combinedDrawable); + } else if (child instanceof ChartHeaderView) { + ((ChartHeaderView) child).recolor(); + } else if (child instanceof OverviewCell) { + ((OverviewCell) child).updateColors(); + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + if (child instanceof EmptyCell) { + child.setBackgroundColor(Theme.getColor(Theme.key_windowBackgroundWhite)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index fe5453a0d..22ba628f4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -46,6 +46,24 @@ import android.os.Build; import android.os.Bundle; import android.os.SystemClock; import android.provider.Settings; + +import androidx.annotation.Keep; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.collection.ArrayMap; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.core.view.ViewCompat; +import androidx.core.widget.NestedScrollView; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; +import androidx.exifinterface.media.ExifInterface; +import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScrollerEnd; +import androidx.recyclerview.widget.RecyclerView; + import android.text.Layout; import android.text.Selection; import android.text.Spannable; @@ -163,6 +181,7 @@ import org.telegram.ui.ActionBar.ActionBarMenuSubItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; import org.telegram.ui.ActionBar.AdjustPanLayoutHelper; import org.telegram.ui.ActionBar.AlertDialog; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.ActionBar.Theme; @@ -222,6 +241,7 @@ import java.lang.reflect.Method; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -296,7 +316,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private ActionBarMenuItem shareItem; private LinearLayout itemsLayout; private Map actionBarItemsVisibility = new HashMap<>(3); + private LinearLayout bottomButtonsLayout; private ImageView shareButton; + private ImageView paintButton; private BackgroundDrawable backgroundDrawable = new BackgroundDrawable(0xff000000); private Paint blackPaint = new Paint(); private CheckBox checkImageView; @@ -465,6 +487,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private long lastBufferedPositionCheck; private View playButtonAccessibilityOverlay; private StickersAlert masksAlert; + private int lastImageId = -1; private int keyboardSize; @@ -849,6 +872,39 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private class SavedState { + + private int index; + private ArrayList messages; + private PhotoViewerProvider provider; + + public SavedState(int index, ArrayList messages, PhotoViewerProvider provider) { + this.messages = messages; + this.index = index; + this.provider = provider; + } + + public void restore() { + placeProvider = provider; + + if (Build.VERSION.SDK_INT >= 21) { + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | + WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + } else { + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + windowLayoutParams.softInputMode = (useSmoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; + windowView.setFocusable(false); + containerView.setFocusable(false); + backgroundDrawable.setAlpha(255); + containerView.setAlpha(1.0f); + + onPhotoShow(null, null, null, null, messages, null, null, index, provider.getPlaceForPhoto(messages.get(index), null, index, true)); + } + } + private int currentImageHasFace; private String currentImageFaceKey; private PaintingOverlay paintingOverlay; @@ -951,20 +1007,31 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private ArrayList avatarsArr = new ArrayList<>(); private ArrayList imagesArrLocals = new ArrayList<>(); private ImageLocation currentAvatarLocation = null; + private SavedState savedState = null; private PageBlocksAdapter pageBlocksAdapter; public interface PageBlocksAdapter { int getItemsCount(); + TLRPC.PageBlock get(int index); + List getAll(); + boolean isVideo(int index); + TLObject getMedia(int index); + File getFile(int index); + String getFileName(int index); + CharSequence getCaption(int index); + TLRPC.PhotoSize getFileLocation(TLObject media, int[] size); + void updateSlideshowCell(TLRPC.PageBlock currentPageBlock); + Object getParentObject(); } @@ -1625,30 +1692,55 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public interface PhotoViewerProvider { PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index, boolean needPreview); + ImageReceiver.BitmapHolder getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); + void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index); + void willHidePhotoViewer(); + boolean isPhotoChecked(int index); + int setPhotoChecked(int index, VideoEditedInfo videoEditedInfo); + int setPhotoUnchecked(Object photoEntry); + boolean cancelButtonPressed(); + void needAddMorePhotos(); + void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate); + int getSelectedCount(); + void updatePhotoAtIndex(int index); + boolean allowCaption(); + boolean scaleToFill(); + ArrayList getSelectedPhotosOrder(); + HashMap getSelectedPhotos(); + boolean canScrollAway(); + int getPhotoIndex(int index); + void deleteImageAtIndex(int index); + String getDeleteMessageString(); + boolean canCaptureMorePhotos(); + void openPhotoForEdit(String file, String thumb, boolean isVideo); + int getTotalImageCount(); + boolean loadMore(); + CharSequence getTitleFor(int index); + CharSequence getSubtitleFor(int index); } @@ -1689,19 +1781,35 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (photoFilterView != null) { photoFilterView.setTranslationY(y); } - if (photoPaintView != null) { - photoPaintView.setTranslationY(y); - } +// if (pickerView != null) { pickerView.setTranslationY(y); } if (pickerViewSendButton != null) { pickerViewSendButton.setTranslationY(y); } - if (captionEditText != null) { - float p = progress < 0.5f ? 0 : (progress - 0.5f) / 0.5f; - captionEditText.setAlpha(p); - captionEditText.setTranslationY(y - this.keyboardSize + AndroidUtilities.dp(keyboardSize / 2) * (1f - progress)); + + if (currentEditMode == 3) { + if (captionEditText != null) { + captionEditText.setTranslationY(y); + } + + if (photoPaintView != null) { + photoPaintView.setTranslationY(0); + photoPaintView.getColorPicker().setTranslationY(y); + photoPaintView.getToolsView().setTranslationY(y); + photoPaintView.getCurtainView().setTranslationY(y); + } + } else { + + if (photoPaintView != null) { + photoPaintView.setTranslationY(y); + } + if (captionEditText != null) { + float p = progress < 0.5f ? 0 : (progress - 0.5f) / 0.5f; + captionEditText.setAlpha(p); + captionEditText.setTranslationY(y - this.keyboardSize + AndroidUtilities.dp(keyboardSize / 2) * (1f - progress)); + } } if (muteItem != null) { muteItem.setTranslationY(y); @@ -1866,7 +1974,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat protected void onLayout(boolean changed, int _l, int t, int _r, int _b) { final int count = getChildCount(); int keyboardHeight = getKeyboardHeight(); - keyboardSize = SharedConfig.smoothKeyboard ? 0 : keyboardHeight; + keyboardSize = keyboardHeight; int paddingBottom = keyboardHeight <= AndroidUtilities.dp(20) && !AndroidUtilities.isInMultiwindow ? captionEditText.getEmojiPadding() : 0; for (int i = 0; i < count; i++) { @@ -1983,6 +2091,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return false; } } + if (child == mentionListView) { + canvas.save(); + canvas.clipRect(child.getX(), child.getY(), child.getX() + child.getWidth(), child.getY() + child.getHeight()); + boolean r = super.drawChild(canvas, child, drawingTime); + canvas.restore(); + return r; + } } else if (child == cameraItem || child == muteItem || child == pickerView || child == videoTimelineView || child == pickerViewSendButton || child == captionTextViewSwitcher || muteItem.getVisibility() == VISIBLE && child == bottomLayout) { if (captionEditText.isPopupAnimatig()) { child.setTranslationY(captionEditText.getEmojiPadding()); @@ -3281,7 +3396,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (animationInProgress == 3) { blackPaint.setAlpha((int) (255 * (1.0f - animatingImageView.getAnimationProgress()))); } else { - blackPaint.setAlpha(255); + blackPaint.setAlpha(backgroundDrawable.getAlpha()); } canvas.drawRect(0, getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight() + insets.getSystemWindowInsetBottom(), blackPaint); } @@ -3383,7 +3498,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } File f = null; - boolean isVideo = false; + final boolean isVideo; if (currentMessageObject != null) { if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && currentMessageObject.messageOwner.media.webpage != null && currentMessageObject.messageOwner.media.webpage.document == null) { TLObject fileLocation = getFileLocation(currentIndex, null); @@ -3394,14 +3509,18 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat isVideo = currentMessageObject.isVideo(); } else if (currentFileLocationVideo != null) { f = FileLoader.getPathToAttach(getFileLocation(currentFileLocationVideo), getFileLocationExt(currentFileLocationVideo), avatarsDialogId != 0 || isEvent); + isVideo = false; } else if (pageBlocksAdapter != null) { f = pageBlocksAdapter.getFile(currentIndex); isVideo = pageBlocksAdapter.isVideo(currentIndex); + } else { + isVideo = false; } if (f != null && f.exists()) { - MediaController.saveFile(f.toString(), parentActivity, isVideo ? 1 : 0, null, null); - BulletinFactory.createSaveToGalleryBulletin(containerView, isVideo, 0xf9222222, 0xffffffff).show(); + MediaController.saveFile(f.toString(), parentActivity, isVideo ? 1 : 0, null, null, () -> { + BulletinFactory.createSaveToGalleryBulletin(containerView, isVideo, 0xf9222222, 0xffffffff).show(); + }); } else { showDownloadAlert(); } @@ -3435,7 +3554,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-lower_part); if (chat != null && chat.migrated_to != null) { args.putInt("migrated_to", lower_part); @@ -4066,12 +4185,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat miniProgressView.setAlpha(0.0f); containerView.addView(miniProgressView, LayoutHelper.createFrame(64, 64, Gravity.CENTER)); + bottomButtonsLayout = new LinearLayout(containerView.getContext()); + bottomButtonsLayout.setOrientation(LinearLayout.HORIZONTAL); + bottomLayout.addView(bottomButtonsLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + + paintButton = new ImageView(containerView.getContext()); + paintButton.setImageResource(R.drawable.photo_paint); + paintButton.setScaleType(ImageView.ScaleType.CENTER); + paintButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); + bottomButtonsLayout.addView(paintButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT)); + paintButton.setOnClickListener(v -> openCurrentPhotoInPaintModeForSelect()); + paintButton.setContentDescription(LocaleController.getString("AccDescrPhotoEditor", R.string.AccDescrPhotoEditor)); + shareButton = new ImageView(containerView.getContext()); shareButton.setImageResource(R.drawable.baseline_share_24); shareButton.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingIcon), PorterDuff.Mode.SRC_IN)); shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setBackgroundDrawable(Theme.createSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); - bottomLayout.addView(shareButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + bottomButtonsLayout.addView(shareButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT)); shareButton.setOnClickListener(v -> onSharePressed()); shareButton.setContentDescription(LocaleController.getString("ShareFile", R.string.ShareFile)); @@ -5144,7 +5275,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat setOffset(captionEditText.getEmojiPadding()); if (captionEditText.getTag() != null) { if (isCurrentVideo) { - actionBar.setTitleAnimated(muteVideo ? LocaleController.getString("GifCaption", R.string.GifCaption) : LocaleController.getString("VideoCaption", R.string.VideoCaption),true, 220); + actionBar.setTitleAnimated(muteVideo ? LocaleController.getString("GifCaption", R.string.GifCaption) : LocaleController.getString("VideoCaption", R.string.VideoCaption), true, 220); } else { actionBar.setTitleAnimated(LocaleController.getString("PhotoCaption", R.string.PhotoCaption), true, 220); } @@ -5650,7 +5781,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat valueAnimator.addUpdateListener(animation -> { float xValue = (float) animation.getAnimatedValue(); float yValue = interpolator == null ? xValue : interpolator.getInterpolation(xValue); - textureImageView.setTranslationX(fromX * (1f - xValue) + toX * xValue); + textureImageView.setTranslationX(fromX * (1f - xValue) + toX * xValue); textureImageView.setTranslationY(fromY2 * (1f - yValue) + toY * yValue); videoTextureView.setTranslationX(fromX * (1f - xValue) + (toX2) * xValue); @@ -5682,7 +5813,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); animatorSet.start(); if (!fromGesture) { - toggleActionBar(false, true, new ActionBarToggleParams().enableStatusBarAnimation(false).animationDuration(250).animationInterpolator(new DecelerateInterpolator())); + toggleActionBar(false, true, new ActionBarToggleParams().enableStatusBarAnimation(false).enableTranslationAnimation(false).animationDuration(250).animationInterpolator(new DecelerateInterpolator())); } } else { switchToInlineRunnable.run(); @@ -6578,7 +6709,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); animatorSet.start(); - toggleActionBar(true, true, new ActionBarToggleParams().enableStatusBarAnimation(false).animationDuration(250).animationInterpolator(interpolator)); + toggleActionBar(true, true, new ActionBarToggleParams().enableStatusBarAnimation(false).enableTranslationAnimation(false).animationDuration(250).animationInterpolator(interpolator)); } else { toggleActionBar(true, false); //containerView.setTranslationY(0); @@ -6795,7 +6926,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat dateTextView.setVisibility(View.VISIBLE); nameTextView.setVisibility(View.VISIBLE); if (allowShare) { - shareButton.setVisibility(View.VISIBLE); + bottomButtonsLayout.setVisibility(View.VISIBLE); } } final boolean shareWasAllowed = allowShare; @@ -6807,7 +6938,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat dateTextView.setAlpha(1f - alpha); nameTextView.setAlpha(1f - alpha); if (shareWasAllowed) { - shareButton.setAlpha(1f - alpha); + bottomButtonsLayout.setAlpha(1f - alpha); } }); anim.addListener(new AnimatorListenerAdapter() { @@ -6819,7 +6950,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat dateTextView.setVisibility(View.GONE); nameTextView.setVisibility(View.GONE); if (shareWasAllowed) { - shareButton.setVisibility(View.GONE); + bottomButtonsLayout.setVisibility(View.GONE); } } } @@ -6834,8 +6965,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat nameTextView.setVisibility(visible ? View.GONE : View.VISIBLE); nameTextView.setAlpha(visible ? 0f : 1f); if (allowShare) { - shareButton.setVisibility(visible ? View.GONE : View.VISIBLE); - shareButton.setAlpha(visible ? 0f : 1f); + bottomButtonsLayout.setVisibility(visible ? View.GONE : View.VISIBLE); + bottomButtonsLayout.setAlpha(visible ? 0f : 1f); } } if (allowShare && pageBlocksAdapter == null) { @@ -7101,7 +7232,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (croppedPaintBitmap != null) { croppedPaintBitmap.recycle(); } - paintBitmap.recycle(); + if (paintBitmap != null) { + paintBitmap.recycle(); + } } else { if (!isCurrentVideo) { TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(croppedBitmap, Bitmap.CompressFormat.JPEG, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 87, false, 101, 101); @@ -7292,14 +7425,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (currentEditMode == 1) { entry.isCropped = true; - cropItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); + cropItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } else if (currentEditMode == 2) { entry.isFiltered = true; - tuneItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); + tuneItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } else if (currentEditMode == 3) { if (hasChanged) { entry.isPainted = true; - paintItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); + paintItem.setColorFilter(new PorterDuffColorFilter(Theme.getColor(Theme.key_dialogFloatingButton), PorterDuff.Mode.SRC_IN)); } } @@ -7588,6 +7721,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat updateMinMax(scale); containerView.invalidate(); + if (savedState != null) { + savedState.restore(); + savedState = null; + final ActionBarToggleParams toggleParams = new ActionBarToggleParams().enableStatusBarAnimation(false); + toggleActionBar(false, false, toggleParams); + toggleActionBar(true, true, toggleParams); + return; + } + AnimatorSet animatorSet = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0)); @@ -7932,72 +8074,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat changeModeAnimation.start(); } else if (mode == 3) { startVideoPlayer(); - if (photoPaintView == null) { - int w; - int h; - if (videoTextureView != null) { - VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; - w = textureView.getVideoWidth(); - h = textureView.getVideoHeight(); - while (w > 1280 || h > 1280) { - w /= 2; - h /= 2; - } - } else { - w = centerImage.getBitmapWidth(); - h = centerImage.getBitmapHeight(); - } - Bitmap bitmap = paintingOverlay.getBitmap(); - if (bitmap == null) { - bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - } - MediaController.CropState state; - if (sendPhotoType == SELECT_TYPE_AVATAR) { - state = new MediaController.CropState(); - state.transformRotation = cropTransform.getOrientation(); - } else { - state = editState.cropState; - } - photoPaintView = new PhotoPaintView(parentActivity, bitmap, isCurrentVideo ? null : centerImage.getBitmap(), centerImage.getOrientation(), editState.mediaEntities, state, () -> paintingOverlay.hideBitmap()) { - @Override - protected void onOpenCloseStickersAlert(boolean open) { - if (videoPlayer == null) { - return; - } - manuallyPaused = false; - cancelVideoPlayRunnable(); - if (open) { - videoPlayer.pause(); - } else { - videoPlayer.play(); - } - } + createPaintView(); - @Override - protected void didSetAnimatedSticker(RLottieDrawable drawable) { - if (videoPlayer == null) { - return; - } - drawable.setProgressMs(videoPlayer.getCurrentPosition() - (startTime > 0 ? startTime / 1000 : 0)); - } - }; - containerView.addView(photoPaintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - photoPaintView.getDoneTextView().setOnClickListener(v -> { - applyCurrentEditMode(); - switchToEditMode(0); - }); - photoPaintView.getCancelTextView().setOnClickListener(v -> photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(0))); - photoPaintView.getColorPicker().setTranslationY(AndroidUtilities.dp(126)); - photoPaintView.getToolsView().setTranslationY(AndroidUtilities.dp(126)); - } changeModeAnimation = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); - arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); - arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); - arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, 0, -actionBar.getHeight())); + arrayList.add(ObjectAnimator.ofFloat(pickerView, View.TRANSLATION_Y, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); + arrayList.add(ObjectAnimator.ofFloat(pickerViewSendButton, View.TRANSLATION_Y, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); + arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, -actionBar.getHeight())); if (needCaptionLayout) { - arrayList.add(ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, 0, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); + arrayList.add(ObjectAnimator.ofFloat(captionTextViewSwitcher, View.TRANSLATION_Y, AndroidUtilities.dp(isCurrentVideo ? 154 : 96))); } if (sendPhotoType == 0 || sendPhotoType == 4) { arrayList.add(ObjectAnimator.ofFloat(checkImageView, View.ALPHA, 1, 0)); @@ -8019,98 +8105,168 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat changeModeAnimation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - changeModeAnimation = null; - pickerView.setVisibility(View.GONE); - pickerViewSendButton.setVisibility(View.GONE); - cameraItem.setVisibility(View.GONE); - muteItem.setVisibility(View.GONE); - if (photoCropView != null) { - photoCropView.setVisibility(View.INVISIBLE); - } - selectedPhotosListView.setVisibility(View.GONE); - selectedPhotosListView.setAlpha(0.0f); - selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); - photosCounterView.setRotationX(0.0f); - selectedPhotosListView.setEnabled(false); - isPhotosListViewVisible = false; - if (needCaptionLayout) { - captionTextViewSwitcher.setVisibility(View.INVISIBLE); - } - if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { - checkImageView.setVisibility(View.GONE); - photosCounterView.setVisibility(View.GONE); - } - - Bitmap bitmap = centerImage.getBitmap(); - if (bitmap != null) { - int bitmapWidth = centerImage.getBitmapWidth(); - int bitmapHeight = centerImage.getBitmapHeight(); - - float oldScale; - float newScale; - if (sendPhotoType == SELECT_TYPE_AVATAR) { - animateToY = AndroidUtilities.dp(12); - if (cropTransform.getOrientation() == 90 || cropTransform.getOrientation() == 270) { - int temp = bitmapWidth; - bitmapWidth = bitmapHeight; - bitmapHeight = temp; - } - } else { - animateToY = -AndroidUtilities.dp(44) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight / 2 : 0); - if (editState.cropState != null) { - if (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270) { - int temp = bitmapWidth; - bitmapWidth = bitmapHeight; - bitmapHeight = temp; - } - bitmapWidth *= editState.cropState.cropPw; - bitmapHeight *= editState.cropState.cropPh; - } - } - oldScale = Math.min(getContainerViewWidth() / (float) bitmapWidth, getContainerViewHeight() / (float) bitmapHeight); - newScale = Math.min(getContainerViewWidth(3) / (float) bitmapWidth, getContainerViewHeight(3) / (float) bitmapHeight); - animateToScale = newScale / oldScale; - animateToX = getLeftInset() / 2 - getRightInset() / 2; - animationStartTime = System.currentTimeMillis(); - zoomAnimation = true; - } - - imageMoveAnimation = new AnimatorSet(); - imageMoveAnimation.playTogether( - ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), - ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0), - ObjectAnimator.ofFloat(photoPaintView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0) - ); - imageMoveAnimation.setDuration(200); - imageMoveAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - - } - - @Override - public void onAnimationEnd(Animator animation) { - photoPaintView.init(); - paintingOverlay.hideEntities(); - imageMoveAnimation = null; - currentEditMode = mode; - switchingToMode = -1; - animateToScale = 1; - animateToX = 0; - animateToY = 0; - scale = 1; - updateMinMax(scale); - padImageForHorizontalInsets = true; - containerView.invalidate(); - } - }); - imageMoveAnimation.start(); + switchToPaintMode(); } }); changeModeAnimation.start(); } } + private void createPaintView() { + if (photoPaintView == null) { + int w; + int h; + if (videoTextureView != null) { + VideoEditTextureView textureView = (VideoEditTextureView) videoTextureView; + w = textureView.getVideoWidth(); + h = textureView.getVideoHeight(); + while (w > 1280 || h > 1280) { + w /= 2; + h /= 2; + } + } else { + w = centerImage.getBitmapWidth(); + h = centerImage.getBitmapHeight(); + } + Bitmap bitmap = paintingOverlay.getBitmap(); + if (bitmap == null) { + bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + } + MediaController.CropState state; + if (sendPhotoType == SELECT_TYPE_AVATAR) { + state = new MediaController.CropState(); + state.transformRotation = cropTransform.getOrientation(); + } else { + state = editState.cropState; + } + photoPaintView = new PhotoPaintView(parentActivity, bitmap, isCurrentVideo ? null : centerImage.getBitmap(), centerImage.getOrientation(), editState.mediaEntities, state, () -> paintingOverlay.hideBitmap()) { + @Override + protected void onOpenCloseStickersAlert(boolean open) { + if (videoPlayer == null) { + return; + } + manuallyPaused = false; + cancelVideoPlayRunnable(); + if (open) { + videoPlayer.pause(); + } else { + videoPlayer.play(); + } + } + + @Override + protected void didSetAnimatedSticker(RLottieDrawable drawable) { + if (videoPlayer == null) { + return; + } + drawable.setProgressMs(videoPlayer.getCurrentPosition() - (startTime > 0 ? startTime / 1000 : 0)); + } + }; + containerView.addView(photoPaintView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + photoPaintView.getDoneTextView().setOnClickListener(v -> { + savedState = null; + applyCurrentEditMode(); + switchToEditMode(0); + }); + photoPaintView.getCancelTextView().setOnClickListener(v -> closePaintMode()); + photoPaintView.getColorPicker().setTranslationY(AndroidUtilities.dp(126)); + photoPaintView.getToolsView().setTranslationY(AndroidUtilities.dp(126)); + } + } + + private void closePaintMode() { + photoPaintView.maybeShowDismissalAlert(PhotoViewer.this, parentActivity, () -> switchToEditMode(0)); + } + + private void switchToPaintMode() { + changeModeAnimation = null; + pickerView.setVisibility(View.GONE); + pickerViewSendButton.setVisibility(View.GONE); + cameraItem.setVisibility(View.GONE); + muteItem.setVisibility(View.GONE); + if (photoCropView != null) { + photoCropView.setVisibility(View.INVISIBLE); + } + selectedPhotosListView.setVisibility(View.GONE); + selectedPhotosListView.setAlpha(0.0f); + selectedPhotosListView.setTranslationY(-AndroidUtilities.dp(10)); + photosCounterView.setRotationX(0.0f); + selectedPhotosListView.setEnabled(false); + isPhotosListViewVisible = false; + if (needCaptionLayout) { + captionTextViewSwitcher.setVisibility(View.INVISIBLE); + } + if (sendPhotoType == 0 || sendPhotoType == 4 || (sendPhotoType == 2 || sendPhotoType == 5) && imagesArrLocals.size() > 1) { + checkImageView.setVisibility(View.GONE); + photosCounterView.setVisibility(View.GONE); + } + + Bitmap bitmap = centerImage.getBitmap(); + if (bitmap != null) { + int bitmapWidth = centerImage.getBitmapWidth(); + int bitmapHeight = centerImage.getBitmapHeight(); + + float oldScale; + float newScale; + if (sendPhotoType == SELECT_TYPE_AVATAR) { + animateToY = AndroidUtilities.dp(12); + if (cropTransform.getOrientation() == 90 || cropTransform.getOrientation() == 270) { + int temp = bitmapWidth; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + } + } else { + animateToY = -AndroidUtilities.dp(44) + (isStatusBarVisible() ? AndroidUtilities.statusBarHeight / 2 : 0); + if (editState.cropState != null) { + if (editState.cropState.transformRotation == 90 || editState.cropState.transformRotation == 270) { + int temp = bitmapWidth; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + } + bitmapWidth *= editState.cropState.cropPw; + bitmapHeight *= editState.cropState.cropPh; + } + } + oldScale = Math.min(getContainerViewWidth() / (float) bitmapWidth, getContainerViewHeight() / (float) bitmapHeight); + newScale = Math.min(getContainerViewWidth(3) / (float) bitmapWidth, getContainerViewHeight(3) / (float) bitmapHeight); + animateToScale = newScale / oldScale; + animateToX = getLeftInset() / 2 - getRightInset() / 2; + animationStartTime = System.currentTimeMillis(); + zoomAnimation = true; + } + + imageMoveAnimation = new AnimatorSet(); + imageMoveAnimation.playTogether( + ObjectAnimator.ofFloat(PhotoViewer.this, AnimationProperties.PHOTO_VIEWER_ANIMATION_VALUE, 0, 1), + ObjectAnimator.ofFloat(photoPaintView.getColorPicker(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0), + ObjectAnimator.ofFloat(photoPaintView.getToolsView(), View.TRANSLATION_Y, AndroidUtilities.dp(126), 0) + ); + imageMoveAnimation.setDuration(200); + imageMoveAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + photoPaintView.init(); + paintingOverlay.hideEntities(); + imageMoveAnimation = null; + currentEditMode = 3; + switchingToMode = -1; + animateToScale = 1; + animateToX = 0; + animateToY = 0; + scale = 1; + updateMinMax(scale); + padImageForHorizontalInsets = true; + containerView.invalidate(); + } + }); + imageMoveAnimation.start(); + } + private void toggleCheckImageView(boolean show) { AnimatorSet animatorSet = new AnimatorSet(); ArrayList arrayList = new ArrayList<>(); @@ -8209,6 +8365,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public int animationDuration = 200; public Interpolator animationInterpolator; public boolean enableStatusBarAnimation = true; + public boolean enableTranslationAnimation = true; public ActionBarToggleParams() { } @@ -8218,6 +8375,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return this; } + public ActionBarToggleParams enableTranslationAnimation(boolean val) { + enableTranslationAnimation = val; + return this; + } + public ActionBarToggleParams animationDuration(int val) { animationDuration = val; return this; @@ -8267,20 +8429,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat final float offsetY = AndroidUtilities.dpf2(24); - videoPlayerControlFrameLayout.setSeekBarTransitionEnabled(params.enableStatusBarAnimation && playerLooping); - videoPlayerControlFrameLayout.setTranslationYAnimationEnabled(params.enableStatusBarAnimation); + videoPlayerControlFrameLayout.setSeekBarTransitionEnabled(params.enableTranslationAnimation && playerLooping); + videoPlayerControlFrameLayout.setTranslationYAnimationEnabled(params.enableTranslationAnimation); if (animated) { ArrayList arrayList = new ArrayList<>(); arrayList.add(ObjectAnimator.ofFloat(actionBar, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableStatusBarAnimation) { + if (params.enableTranslationAnimation) { arrayList.add(ObjectAnimator.ofFloat(actionBar, View.TRANSLATION_Y, show ? 0 : -offsetY)); } else { actionBar.setTranslationY(0); } if (bottomLayout != null) { arrayList.add(ObjectAnimator.ofFloat(bottomLayout, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableStatusBarAnimation) { + if (params.enableTranslationAnimation) { arrayList.add(ObjectAnimator.ofFloat(bottomLayout, View.TRANSLATION_Y, show ? 0 : offsetY)); } else { bottomLayout.setTranslationY(0); @@ -8292,14 +8454,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat videoPlayerControlFrameLayout.setProgress(show ? 1.0f : 0.0f); } arrayList.add(ObjectAnimator.ofFloat(groupedPhotosListView, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableStatusBarAnimation) { + if (params.enableTranslationAnimation) { arrayList.add(ObjectAnimator.ofFloat(groupedPhotosListView, View.TRANSLATION_Y, show ? 0 : offsetY)); } else { groupedPhotosListView.setTranslationY(0); } if (!needCaptionLayout && captionScrollView != null) { arrayList.add(ObjectAnimator.ofFloat(captionScrollView, View.ALPHA, show ? 1.0f : 0.0f)); - if (params.enableStatusBarAnimation) { + if (params.enableTranslationAnimation) { arrayList.add(ObjectAnimator.ofFloat(captionScrollView, View.TRANSLATION_Y, show ? 0 : offsetY)); } else { captionScrollView.setTranslationY(0); @@ -8695,7 +8857,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, ImageLocation imageLocation, ImageLocation videoLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, int index, final PlaceProviderObject object) { + private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, ImageLocation imageLocation, ImageLocation videoLocation, final ArrayList messages, final ArrayList documents, final List photos, int index, final PlaceProviderObject object) { classGuid = ConnectionsManager.generateClassGuid(); currentMessageObject = null; currentFileLocation = null; @@ -8765,7 +8927,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat bottomLayout.setTag(1); bottomLayout.setTranslationY(0); captionTextViewSwitcher.setTranslationY(0); - shareButton.setVisibility(View.GONE); + bottomButtonsLayout.setVisibility(View.GONE); + paintButton.setVisibility(View.GONE); if (qualityChooseView != null) { qualityChooseView.setVisibility(View.INVISIBLE); qualityPicker.setVisibility(View.INVISIBLE); @@ -8940,10 +9103,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imagesArrLocationsSizes.add(object != null ? object.size : 0); imagesArrMessages.add(null); avatarsArr.add(new TLRPC.TL_photoEmpty()); - shareButton.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); + bottomButtonsLayout.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); allowShare = true; menuItem.hideSubItem(gallery_menu_showall); - if (shareButton.getVisibility() == View.VISIBLE) { + if (bottomButtonsLayout.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); @@ -9088,6 +9251,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private boolean canSendMediaToParentChatActivity() { + return parentChatActivity != null && (parentChatActivity.currentUser != null || parentChatActivity.currentChat != null && ChatObject.canSendMedia(parentChatActivity.currentChat)); + } + private void setDoubleTapEnabled(boolean value) { doubleTapEnabled = value; gestureDetector.setOnDoubleTapListener(value ? this : null); @@ -9212,7 +9379,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.hideSubItem(gallery_menu_delete); } allowShare = true; - shareButton.setVisibility(View.VISIBLE); + bottomButtonsLayout.setVisibility(View.VISIBLE); + paintButton.setVisibility(View.GONE); actionBar.setTitle(LocaleController.getString("AttachGif", R.string.AttachGif)); } else { if (totalImagesCount + totalImagesCountMerge != 0 && !needSearchImageInArr) { @@ -9278,7 +9446,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (newMessageObject.messageOwner.ttl != 0 && newMessageObject.messageOwner.ttl < 60 * 60) { allowShare = false; menuItem.hideSubItem(gallery_menu_save); - shareButton.setVisibility(View.GONE); + bottomButtonsLayout.setVisibility(View.GONE); menuItem.hideSubItem(gallery_menu_scan); menuItem.hideSubItem(gallery_menu_share); } else { @@ -9287,13 +9455,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.showSubItem(gallery_menu_scan); shareButton.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); if (shareButton.getVisibility() == View.VISIBLE) { - menuItem.hideSubItem(gallery_menu_share); - } else { - menuItem.showSubItem(gallery_menu_share); + paintButton.setVisibility(!isVideo && canSendMediaToParentChatActivity() ? View.VISIBLE : View.GONE); + bottomButtonsLayout.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); + if (bottomButtonsLayout.getVisibility() == View.VISIBLE) { + menuItem.hideSubItem(gallery_menu_share); + } else { + menuItem.showSubItem(gallery_menu_share); + } } } + groupedPhotosListView.fillList(); } - groupedPhotosListView.fillList(); } else if (!secureDocuments.isEmpty()) { allowShare = false; menuItem.hideSubItem(gallery_menu_save); @@ -9358,8 +9530,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat menuItem.showSubItem(gallery_menu_save); menuItem.showSubItem(gallery_menu_scan); allowShare = true; - shareButton.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); - if (shareButton.getVisibility() == View.VISIBLE) { + bottomButtonsLayout.setVisibility(!videoPlayerControlVisible ? View.VISIBLE : View.GONE); + if (bottomButtonsLayout.getVisibility() == View.VISIBLE) { menuItem.hideSubItem(gallery_menu_share); } else { menuItem.showSubItem(gallery_menu_share); @@ -9751,6 +9923,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat docNameTextView.setText(file.getName()); docInfoTextView.setText(builder); } + sameImage = savedState != null; } else if (object instanceof MediaController.SearchImage) { MediaController.SearchImage searchImage = (MediaController.SearchImage) object; currentPathObject = searchImage.getPathToAttach(); @@ -9824,6 +9997,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateToY = 0; animateToScale = 1; animationStartTime = 0; + zoomAnimation = false; imageMoveAnimation = null; changeModeAnimation = null; if (aspectRatioFrameLayout != null) { @@ -9906,7 +10080,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat detectFaces(); } - private void setCurrentCaption(MessageObject messageObject, final CharSequence caption, boolean animated) { + private void setCurrentCaption(MessageObject messageObject, final CharSequence caption, + boolean animated) { if (needCaptionLayout) { if (captionTextViewSwitcher.getParent() != pickerView) { if (captionContainer != null) { @@ -10625,7 +10800,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (Instance != null) { result = Instance.isVisible && !Instance.disableShowCheck && object != null && ((Instance.currentFileLocation != null && object.local_id == Instance.currentFileLocation.location.local_id && object.volume_id == Instance.currentFileLocation.location.volume_id && object.dc_id == Instance.currentFileLocation.dc_id) || - (Instance.currentFileLocationVideo != null && object.local_id == Instance.currentFileLocationVideo.location.local_id && object.volume_id == Instance.currentFileLocationVideo.location.volume_id && object.dc_id == Instance.currentFileLocationVideo.dc_id)); + (Instance.currentFileLocationVideo != null && object.local_id == Instance.currentFileLocationVideo.location.local_id && object.volume_id == Instance.currentFileLocationVideo.location.volume_id && object.dc_id == Instance.currentFileLocationVideo.dc_id)); } return result; } @@ -10665,39 +10840,49 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } - public boolean openPhoto(final MessageObject messageObject, ChatActivity chatActivity, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { + public boolean openPhoto(final MessageObject messageObject, ChatActivity chatActivity, + long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messageObject, null, null, null, null, null, null, 0, provider, chatActivity, dialogId, mergeDialogId, true, null); } - public boolean openPhoto(final MessageObject messageObject, long dialogId, long mergeDialogId, final PhotoViewerProvider provider, boolean fullScreenVideo) { + public boolean openPhoto(final MessageObject messageObject, long dialogId, + long mergeDialogId, final PhotoViewerProvider provider, boolean fullScreenVideo) { return openPhoto(messageObject, null, null, null, null, null, null, 0, provider, null, dialogId, mergeDialogId, fullScreenVideo, null); } - public boolean openPhoto(final TLRPC.FileLocation fileLocation, final PhotoViewerProvider provider) { + public boolean openPhoto(final TLRPC.FileLocation fileLocation, + final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, null, null, null, null, null, 0, provider, null, 0, 0, true, null); } - public boolean openPhotoWithVideo(final TLRPC.FileLocation fileLocation, ImageLocation videoLocation, final PhotoViewerProvider provider) { + public boolean openPhotoWithVideo(final TLRPC.FileLocation fileLocation, ImageLocation + videoLocation, final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, null, videoLocation, null, null, null, 0, provider, null, 0, 0, true, null); } - public boolean openPhoto(final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final PhotoViewerProvider provider) { + public boolean openPhoto(final TLRPC.FileLocation fileLocation, + final ImageLocation imageLocation, final PhotoViewerProvider provider) { return openPhoto(null, fileLocation, imageLocation, null, null, null, null, 0, provider, null, 0, 0, true, null); } - public boolean openPhoto(final ArrayList messages, final int index, long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { + public boolean openPhoto(final ArrayList messages, final int index, + long dialogId, long mergeDialogId, final PhotoViewerProvider provider) { return openPhoto(messages.get(index), null, null, null, messages, null, null, index, provider, null, dialogId, mergeDialogId, true, null); } - public boolean openPhoto(final ArrayList documents, final int index, final PhotoViewerProvider provider) { + public boolean openPhoto(final ArrayList documents, final int index, + final PhotoViewerProvider provider) { return openPhoto(null, null, null, null, null, documents, null, index, provider, null, 0, 0, true, null); } - public boolean openPhoto(int index, PageBlocksAdapter pageBlocksAdapter, PhotoViewerProvider provider) { + public boolean openPhoto(int index, PageBlocksAdapter + pageBlocksAdapter, PhotoViewerProvider provider) { return openPhoto(null, null, null, null, null, null, null, index, provider, null, 0, 0, true, pageBlocksAdapter); } - public boolean openPhotoForSelect(final ArrayList photos, final int index, int type, boolean documentsPicker, final PhotoViewerProvider provider, ChatActivity chatActivity) { + public boolean openPhotoForSelect(final ArrayList photos, final int index, + int type, boolean documentsPicker, final PhotoViewerProvider provider, ChatActivity + chatActivity) { isDocumentsPicker = documentsPicker; if (pickerViewSendButton != null) { FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) pickerViewSendButton.getLayoutParams(); @@ -10763,6 +10948,118 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return openPhoto(null, null, null, null, null, null, photos, index, provider, chatActivity, 0, 0, true, null); } + private void openCurrentPhotoInPaintModeForSelect() { + if (!canSendMediaToParentChatActivity()) { + return; + } + + File file = null; + boolean isVideo = false; + + if (currentMessageObject != null) { + isVideo = currentMessageObject.isVideo(); + if (!TextUtils.isEmpty(currentMessageObject.messageOwner.attachPath)) { + file = new File(currentMessageObject.messageOwner.attachPath); + if (!file.exists()) { + file = null; + } + } + if (file == null) { + file = FileLoader.getPathToMessage(currentMessageObject.messageOwner); + } + } + + if (file != null && file.exists()) { + savedState = new SavedState(currentIndex, new ArrayList<>(imagesArr), placeProvider); + + final ActionBarToggleParams toggleParams = new ActionBarToggleParams().enableStatusBarAnimation(false); + toggleActionBar(false, true, toggleParams); + + File finalFile = file; + boolean finalIsVideo = isVideo; + AndroidUtilities.runOnUIThread(() -> { + int orientation = 0; + try { + ExifInterface ei = new ExifInterface(finalFile.getAbsolutePath()); + int exif = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); + switch (exif) { + case ExifInterface.ORIENTATION_ROTATE_90: + orientation = 90; + break; + case ExifInterface.ORIENTATION_ROTATE_180: + orientation = 180; + break; + case ExifInterface.ORIENTATION_ROTATE_270: + orientation = 270; + break; + } + } catch (Exception e) { + FileLog.e(e); + } + final MediaController.PhotoEntry photoEntry = new MediaController.PhotoEntry(0, lastImageId--, 0, finalFile.getAbsolutePath(), orientation, finalIsVideo, 0, 0, 0); + + sendPhotoType = 2; + doneButtonPressed = false; + placeProvider = new EmptyPhotoViewerProvider() { + + private final ImageReceiver.BitmapHolder thumbHolder = centerImage.getBitmapSafe(); + + @Override + public ImageReceiver.BitmapHolder getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + return thumbHolder; + } + + @Override + public void sendButtonPressed(int index, VideoEditedInfo videoEditedInfo, boolean notify, int scheduleDate) { + if (parentChatActivity != null) { + parentChatActivity.sendMedia(photoEntry, videoEditedInfo, notify, scheduleDate); + } + } + + @Override + public boolean canCaptureMorePhotos() { + return false; + } + }; + selectedPhotosAdapter.notifyDataSetChanged(); + + if (velocityTracker == null) { + velocityTracker = VelocityTracker.obtain(); + } + + togglePhotosListView(false, false); + toggleActionBar(true, false); + + if (Build.VERSION.SDK_INT >= 21) { + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | + WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + } else { + windowLayoutParams.flags = 0; + } + windowLayoutParams.softInputMode = (useSmoothKeyboard ? WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN : WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) | WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.updateViewLayout(windowView, windowLayoutParams); + windowView.setFocusable(true); + containerView.setFocusable(true); + backgroundDrawable.setAlpha(255); + containerView.setAlpha(1.0f); + + onPhotoShow(null, null, null, null, null, null, Collections.singletonList(photoEntry), 0, null); + + pickerView.setTranslationY(AndroidUtilities.dp(isCurrentVideo ? 154 : 96)); + pickerViewSendButton.setTranslationY(AndroidUtilities.dp(isCurrentVideo ? 154 : 96)); + actionBar.setTranslationY(-actionBar.getHeight()); + captionTextViewSwitcher.setTranslationY(AndroidUtilities.dp(isCurrentVideo ? 154 : 96)); + + createPaintView(); + switchToPaintMode(); + }, toggleParams.animationDuration); + } else { + showDownloadAlert(); + } + } + private boolean checkAnimation() { if (animationInProgress != 0) { if (Math.abs(transitionAnimationStartTime - System.currentTimeMillis()) >= 500) { @@ -10813,7 +11110,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat padImageForHorizontalInsets = true; } - public boolean openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, final ImageLocation videoLocation, final ArrayList messages, final ArrayList documents, final ArrayList photos, final int index, final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, boolean fullScreenVideo, PageBlocksAdapter pageBlocksAdapter) { + public boolean openPhoto(final MessageObject messageObject, + final TLRPC.FileLocation fileLocation, final ImageLocation imageLocation, + final ImageLocation videoLocation, final ArrayList messages, + final ArrayList documents, final ArrayList photos, final int index, + final PhotoViewerProvider provider, ChatActivity chatActivity, long dialogId, long mDialogId, + boolean fullScreenVideo, PageBlocksAdapter pageBlocksAdapter) { if (parentActivity == null || isVisible || provider == null && checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null && documents == null && imageLocation == null && pageBlocksAdapter == null) { return false; } @@ -11067,6 +11369,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.setAlpha(0); animationEndRunnable = () -> { + animationEndRunnable = null; if (containerView == null || windowView == null) { return; } @@ -11212,7 +11515,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public void closePhoto(boolean animated, boolean fromEditMode) { if (!fromEditMode && currentEditMode != 0) { if (currentEditMode == 3 && photoPaintView != null) { - photoPaintView.maybeShowDismissalAlert(this, parentActivity, () -> switchToEditMode(0)); + closePaintMode(); return; } if (currentEditMode == 1) { @@ -11250,6 +11553,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat photoPaintView.shutdown(); containerView.removeView(photoPaintView); photoPaintView = null; + savedState = null; } currentEditMode = 0; } @@ -11465,6 +11769,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animationEndRunnable = () -> { + animationEndRunnable = null; if (Build.VERSION.SDK_INT >= 18) { containerView.setLayerType(View.LAYER_TYPE_NONE, null); } @@ -11499,6 +11804,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ); animationInProgress = 2; animationEndRunnable = () -> { + animationEndRunnable = null; if (containerView == null) { return; } @@ -11515,8 +11821,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void onAnimationEnd(Animator animation) { if (animationEndRunnable != null) { - animationEndRunnable.run(); - animationEndRunnable = null; + ChatActivity chatActivity = parentChatActivity; + if (chatActivity == null && parentAlert != null) { + BaseFragment baseFragment = parentAlert.getBaseFragment(); + if (baseFragment instanceof ChatActivity) { + chatActivity = (ChatActivity) baseFragment; + } + } + if (chatActivity != null) { + chatActivity.doOnIdle(animationEndRunnable); + } else { + animationEndRunnable.run(); + animationEndRunnable = null; + } } } }); @@ -12175,7 +12492,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animateTo(newScale, newTx, newTy, isZoom, 250); } - private void animateTo(float newScale, float newTx, float newTy, boolean isZoom, int duration) { + private void animateTo(float newScale, float newTx, float newTy, boolean isZoom, + int duration) { if (scale == newScale && translationX == newTx && translationY == newTy) { return; } @@ -12422,7 +12740,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (centerImage.hasBitmapImage() || drawTextureView && textureUploaded) { canvas.save(); canvas.translate(containerWidth / 2 + getAdditionX(), containerHeight / 2 + getAdditionY()); - canvas.translate(translateX, currentTranslationY + currentPanTranslationY); + canvas.translate(translateX, currentTranslationY + (currentEditMode != 3 ? currentPanTranslationY : currentPanTranslationY / 2)); canvas.scale(currentScale - scaleDiff, currentScale - scaleDiff); if (currentEditMode == 3 && keyboardSize > AndroidUtilities.dp(20)) { int trueH = getContainerViewHeight(true, 0); @@ -12579,7 +12897,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } if (currentEditMode == 3) { - photoPaintView.setTransform(currentScale, currentTranslationX, currentTranslationY, bitmapWidth * scaleToFitX, bitmapHeight * scaleToFitX); + float add = containerView.adjustPanLayoutHelper.animationInProgress() ? keyboardSize / 2f + currentPanTranslationY / 2 : 0; + photoPaintView.setTransform(currentScale, currentTranslationX, currentTranslationY + add, bitmapWidth * scaleToFitX, bitmapHeight * scaleToFitX); } if (drawCenterImage) { @@ -12662,9 +12981,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } boolean drawProgress; if (isCurrentVideo) { - drawProgress = (videoTimelineView == null || !videoTimelineView.isDragging()) && (sendPhotoType != SELECT_TYPE_AVATAR || manuallyPaused) && (videoPlayer == null || !videoPlayer.isPlaying()); - if (drawProgress && containerView.getKeyboardHeight() > 0) { - drawProgress = captionEditText.getTop() > photoProgressViews[0].getY() + photoProgressViews[0].size; + if (containerView.getKeyboardHeight() > 0) { + drawProgress = false; + } else { + drawProgress = (videoTimelineView == null || !videoTimelineView.isDragging()) && (sendPhotoType != SELECT_TYPE_AVATAR || manuallyPaused) && (videoPlayer == null || !videoPlayer.isPlaying()); } } else { drawProgress = true; @@ -13598,6 +13918,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } + private ByteArrayInputStream cleanBuffer(byte[] data) { byte[] output = new byte[data.length]; int inPos = 0; @@ -13617,7 +13938,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return new ByteArrayInputStream(output, 0, outPos); } - private void processOpenVideo(final String videoPath, boolean muted, float start, float end) { + private void processOpenVideo(final String videoPath, boolean muted, float start, + float end) { if (currentLoadingVideoRunnable != null) { Utilities.globalQueue.cancelRunnable(currentLoadingVideoRunnable); currentLoadingVideoRunnable = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index aa90d3218..0ee87e511 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -174,11 +174,11 @@ public class PopupNotificationActivity extends Activity implements NotificationC NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad); classGuid = ConnectionsManager.generateClassGuid(); - statusDrawables[0] = new TypingDotsDrawable(); - statusDrawables[1] = new RecordStatusDrawable(); - statusDrawables[2] = new SendingFileDrawable(); - statusDrawables[3] = new PlayingGameDrawable(); - statusDrawables[4] = new RoundStatusDrawable(); + statusDrawables[0] = new TypingDotsDrawable(false); + statusDrawables[1] = new RecordStatusDrawable(false); + statusDrawables[2] = new SendingFileDrawable(false); + statusDrawables[3] = new PlayingGameDrawable(false); + statusDrawables[4] = new RoundStatusDrawable(false); SizeNotifierFrameLayout contentView = new SizeNotifierFrameLayout(this) { @Override @@ -1341,7 +1341,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC if (currentUser != null && currentUser.id == 777000) { onlineTextView.setText(LocaleController.getString("ServiceNotifications", R.string.ServiceNotifications)); } else { - CharSequence printString = MessagesController.getInstance(currentMessageObject.currentAccount).getPrintingString(currentMessageObject.getDialogId(), 0); + CharSequence printString = MessagesController.getInstance(currentMessageObject.currentAccount).getPrintingString(currentMessageObject.getDialogId(), 0, false); if (printString == null || printString.length() == 0) { lastPrintString = null; setTypingAnimation(false); @@ -1495,7 +1495,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC checkAndUpdateAvatar(); } if ((updateMask & MessagesController.UPDATE_MASK_USER_PRINT) != 0) { - CharSequence printString = MessagesController.getInstance(currentMessageObject.currentAccount).getPrintingString(currentMessageObject.getDialogId(), 0); + CharSequence printString = MessagesController.getInstance(currentMessageObject.currentAccount).getPrintingString(currentMessageObject.getDialogId(), 0, false); if (lastPrintString != null && printString == null || lastPrintString == null && printString != null || lastPrintString != null && printString != null && !lastPrintString.equals(printString)) { updateSubtitle(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index f7be9a32f..ea45e0c0f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -132,6 +132,7 @@ import org.telegram.ui.Components.AnimatedFileDrawable; import org.telegram.ui.Components.AnimationProperties; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatGreetingsView; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.CrossfadeDrawable; @@ -1343,7 +1344,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (ChatObject.isChannel(currentChat)) { getMessagesController().loadFullChat(chat_id, classGuid, true); } else if (chatInfo == null) { - chatInfo = getMessagesStorage().loadChatInfo(chat_id, null, false, false); + chatInfo = getMessagesStorage().loadChatInfo(chat_id, false, null, false, false); } } else { return false; @@ -1687,9 +1688,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (location == null) { return; } - File f = FileLoader.getPathToAttach(location.location, location.imageType == FileLoader.IMAGE_TYPE_ANIMATION ? "mp4" : null, true); - if (f != null && f.exists()) { - MediaController.saveFile(f.toString(), getParentActivity(), 0, null, null); + final boolean isVideo = location.imageType == FileLoader.IMAGE_TYPE_ANIMATION; + File f = FileLoader.getPathToAttach(location.location, isVideo ? "mp4" : null, true); + if (f.exists()) { + MediaController.saveFile(f.toString(), getParentActivity(), 0, null, null, () -> { + if (getParentActivity() == null) { + return; + } + BulletinFactory.createSaveToGalleryBulletin(ProfileActivity.this, isVideo).show(); + }); } } else if (id == logout) { presentFragment(new LogoutActivity()); @@ -2717,7 +2724,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. getMessagesStorage().clearSentMedia(); SharedConfig.setNoSoundHintShowed(false); SharedPreferences.Editor editor = MessagesController.getGlobalMainSettings().edit(); - editor.remove("archivehint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("themehint").remove("filterhint").commit(); + editor.remove("archivehint").remove("proximityhint").remove("archivehint_l").remove("gifhint").remove("soundHint").remove("themehint").remove("filterhint").commit(); SharedConfig.textSelectionHintShows = 0; SharedConfig.lockRecordAudioVideoHint = 0; SharedConfig.stickersReorderingHintUsed = false; @@ -3408,18 +3415,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. builder2.setMessage(LocaleController.formatString("AdminWillBeRemoved", R.string.AdminWillBeRemoved, ContactsController.formatName(user.first_name, user.last_name))); builder2.setPositiveButton(LocaleController.getString("OK", R.string.OK), (dialog, which) -> { if (channelParticipant != null) { - openRightsEdit(action, user.id, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank); + openRightsEdit(action, user, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank, editingAdmin); } else { - openRightsEdit(action, user.id, participant, null, null, ""); + openRightsEdit(action, user, participant, null, null, "", editingAdmin); } }); builder2.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder2.create()); } else { if (channelParticipant != null) { - openRightsEdit(action, user.id, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank); + openRightsEdit(action, user, participant, channelParticipant.admin_rights, channelParticipant.banned_rights, channelParticipant.rank, editingAdmin); } else { - openRightsEdit(action, user.id, participant, null, null, ""); + openRightsEdit(action, user, participant, null, null, "", editingAdmin); } } } @@ -3440,8 +3447,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return true; } - private void openRightsEdit(int action, int user_id, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank) { - ChatRightsEditActivity fragment = new ChatRightsEditActivity(user_id, chat_id, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false, participant); + private void openRightsEdit(int action, TLRPC.User user, TLRPC.ChatParticipant participant, TLRPC.TL_chatAdminRights adminRights, TLRPC.TL_chatBannedRights bannedRights, String rank, boolean editingAdmin) { + boolean[] needShowBulletin = new boolean[1]; + ChatRightsEditActivity fragment = new ChatRightsEditActivity(user.id, chat_id, adminRights, currentChat.default_banned_rights, bannedRights, rank, action, true, false, participant) { + @Override + protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(ProfileActivity.this)) { + BulletinFactory.createPromoteToAdminBulletin(ProfileActivity.this, user.first_name).show(); + } + } + }; fragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -3475,6 +3490,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. chatInfo.participants.participants.set(index, newParticipant); } } + if (rights == 1 && !editingAdmin) { + needShowBulletin[0] = true; + } } else if (action == 1) { if (rights == 0) { if (currentChat.megagroup && chatInfo != null && chatInfo.participants != null) { @@ -3482,9 +3500,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. for (int a = 0; a < chatInfo.participants.participants.size(); a++) { TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) chatInfo.participants.participants.get(a)).channelParticipant; if (p.user_id == participant.user_id) { - if (chatInfo != null) { - chatInfo.participants_count--; - } + chatInfo.participants_count--; chatInfo.participants.participants.remove(a); changed = true; break; @@ -4345,7 +4361,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (chatFull.id == chat_id) { boolean byChannelUsers = (Boolean) args[2]; if (chatInfo instanceof TLRPC.TL_channelFull) { - if (chatFull.participants == null && chatInfo != null) { + if (chatFull.participants == null) { chatFull.participants = chatInfo.participants; } } @@ -5044,12 +5060,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (user != null && !TextUtils.isEmpty(user.username)) { usernameRow = rowCount++; } + if (!isBot && (hasPhone || !hasInfo)) { + phoneRow = rowCount++; + } if (userInfo != null && !TextUtils.isEmpty(userInfo.about)) { userInfoRow = rowCount++; } - if (!isBot && (hasPhone || !hasPhone && !hasInfo)) { - phoneRow = rowCount++; - } if (phoneRow != -1 || userInfoRow != -1 || usernameRow != -1) { notificationsDividerRow = rowCount++; } @@ -5117,7 +5133,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (ChatObject.isChannel(currentChat)) { if (chatInfo != null && currentChat.megagroup && chatInfo.participants != null && !chatInfo.participants.participants.isEmpty()) { - if (!ChatObject.isNotInChat(currentChat) && currentChat.megagroup && ChatObject.canAddUsers(currentChat) && (chatInfo == null || chatInfo.participants_count < getMessagesController().maxMegagroupCount)) { + if (!ChatObject.isNotInChat(currentChat) && ChatObject.canAddUsers(currentChat) && chatInfo.participants_count < getMessagesController().maxMegagroupCount) { addMemberRow = rowCount++; } int count = chatInfo.participants.participants.size(); @@ -5679,6 +5695,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } + if (sharedMediaLayout != null) { + sharedMediaLayout.getSearchItem().requestLayout(); + } } @Override @@ -5697,7 +5716,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (lower_part != 0) { if (lower_part > 0) { args.putInt("user_id", lower_part); - } else if (lower_part < 0) { + } else { args.putInt("chat_id", -lower_part); } } else { @@ -5755,7 +5774,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private Animator searchExpandTransition(boolean enter) { if (enter) { - getParentActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + AndroidUtilities.setAdjustResizeToNothing(getParentActivity(), classGuid); } if (searchViewTransition != null) { searchViewTransition.removeAllListeners(); @@ -5801,10 +5821,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. searchListView.setTranslationY(offset * searchTransitionProgress); emptyView.setTranslationY(offset * searchTransitionProgress); listView.setTranslationY(-offset * (1f - searchTransitionProgress)); + + listView.setScaleX(1f - 0.01f * (1f - searchTransitionProgress)); + listView.setScaleY(1f - 0.01f * (1f - searchTransitionProgress)); + listView.setAlpha(searchTransitionProgress); needLayout(true); listView.setAlpha(progressHalf); - searchListView.setAlpha(1f - progressHalf); + + searchListView.setAlpha(1f - searchTransitionProgress); + searchListView.setScaleX(1f + 0.05f * searchTransitionProgress); + searchListView.setScaleY(1f + 0.05f * searchTransitionProgress); emptyView.setAlpha(1f - progressHalf); avatarContainer.setAlpha(progressHalf); @@ -5844,8 +5871,8 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); - valueAnimator.setDuration(180); - valueAnimator.setInterpolator(AndroidUtilities.decelerateInterpolator); + valueAnimator.setDuration(220); + valueAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT); searchViewTransition = valueAnimator; return valueAnimator; } @@ -5916,34 +5943,32 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. req.flags |= 4; } getConnectionsManager().sendRequest(req, (response, error) -> { - if (error == null) { - TLRPC.User user = getMessagesController().getUser(getUserConfig().getClientUserId()); - if (user == null) { - user = getUserConfig().getCurrentUser(); + AndroidUtilities.runOnUIThread(() -> { + if (error == null) { + TLRPC.User user = getMessagesController().getUser(getUserConfig().getClientUserId()); if (user == null) { - return; + user = getUserConfig().getCurrentUser(); + if (user == null) { + return; + } + getMessagesController().putUser(user, false); + } else { + getUserConfig().setCurrentUser(user); + } + TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; + ArrayList sizes = photos_photo.photo.sizes; + TLRPC.PhotoSize small = FileLoader.getClosestPhotoSizeWithSize(sizes, 150); + TLRPC.PhotoSize big = FileLoader.getClosestPhotoSizeWithSize(sizes, 800); + TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : photos_photo.photo.video_sizes.get(0); + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photos_photo.photo.id; + if (small != null) { + user.photo.photo_small = small.location; + } + if (big != null) { + user.photo.photo_big = big.location; } - getMessagesController().putUser(user, false); - } else { - getUserConfig().setCurrentUser(user); - } - TLRPC.TL_photos_photo photos_photo = (TLRPC.TL_photos_photo) response; - ArrayList sizes = photos_photo.photo.sizes; - TLRPC.PhotoSize small = FileLoader.getClosestPhotoSizeWithSize(sizes, 150); - TLRPC.PhotoSize big = FileLoader.getClosestPhotoSizeWithSize(sizes, 800); - TLRPC.VideoSize videoSize = photos_photo.photo.video_sizes.isEmpty() ? null : photos_photo.photo.video_sizes.get(0); - user.photo = new TLRPC.TL_userProfilePhoto(); - user.photo.photo_id = photos_photo.photo.id; - if (small != null) { - user.photo.photo_small = small.location; - } - if (big != null) { - user.photo.photo_big = big.location; - } else if (small != null) { - user.photo.photo_small = small.location; - } - if (photo != null || video != null) { if (small != null && avatar != null) { File destFile = FileLoader.getPathToAttach(small, true); File src = FileLoader.getPathToAttach(avatar, true); @@ -5962,14 +5987,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. File src = new File(videoPath); src.renameTo(destFile); } + + getMessagesStorage().clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + getMessagesStorage().putUsersAndChats(users, null, false, true); } - getMessagesStorage().clearUserPhotos(user.id); - ArrayList users = new ArrayList<>(); - users.add(user); - getMessagesStorage().putUsersAndChats(users, null, false, true); - } - AndroidUtilities.runOnUIThread(() -> { allowPullingDown = !AndroidUtilities.isTablet() && !isInLandscapeMode && avatarImage.getImageReceiver().hasNotThumb(); avatar = null; avatarBig = null; @@ -6320,7 +6344,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. while (text.contains("\n\n\n")) { text = text.replace("\n\n\n", "\n\n"); } - aboutLinkCell.setText(text, true); + aboutLinkCell.setText(text, ChatObject.isChannel(currentChat) && !currentChat.megagroup); } break; case 4: @@ -6464,10 +6488,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } else if (value == 1) { enabled = true; - } else if (value == 2) { - enabled = false; - } else { - enabled = false; } if (enabled && custom) { val = LocaleController.getString("NotificationsCustom", R.string.NotificationsCustom); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java index 8f45e4d9e..9ebfdd1ab 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SessionsActivity.java @@ -208,7 +208,15 @@ public class SessionsActivity extends BaseFragment implements NotificationCenter listAdapter.notifyDataSetChanged(); undoView.showWithAction(0, UndoView.ACTION_QR_SESSION_ACCEPTED, response); } else { - AndroidUtilities.runOnUIThread(() -> AlertsCreator.showSimpleAlert(SessionsActivity.this, LocaleController.getString("AuthAnotherClient", R.string.AuthAnotherClient), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text)); + AndroidUtilities.runOnUIThread(() -> { + final String text; + if (error.text.equals("AUTH_TOKEN_EXCEPTION")) { + text = LocaleController.getString("AccountAlreadyLoggedIn", R.string.AccountAlreadyLoggedIn); + } else { + text = LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text; + } + AlertsCreator.showSimpleAlert(SessionsActivity.this, LocaleController.getString("AuthAnotherClient", R.string.AuthAnotherClient), text); + }); } })); }); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java index 1fb479cf0..171537ed1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/StatisticActivity.java @@ -71,6 +71,7 @@ import org.telegram.ui.Charts.data.StackLinearChartData; import org.telegram.ui.Charts.view_data.ChartHeaderView; import org.telegram.ui.Charts.view_data.LineViewData; import org.telegram.ui.Charts.view_data.TransitionParams; +import org.telegram.ui.Components.BulletinFactory; import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.CombinedDrawable; import org.telegram.ui.Components.FlatCheckBox; @@ -139,7 +140,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente public StatisticActivity(Bundle args) { super(args); int chatId = args.getInt("chat_id"); - isMegagroup = args.getBoolean("is_megagroup"); + isMegagroup = args.getBoolean("is_megagroup", false); this.chat = getMessagesController().getChatFull(chatId); } @@ -190,6 +191,10 @@ public class StatisticActivity extends BaseFragment implements NotificationCente chartsViewData[7] = createViewData(stats.languages_graph, LocaleController.getString("LanguagesChartTitle", R.string.LanguagesChartTitle), 4, true); chartsViewData[8] = createViewData(stats.mute_graph, LocaleController.getString("NotificationsChartTitle", R.string.NotificationsChartTitle), 0); + if (chartsViewData[2] != null) { + chartsViewData[2].useHourFormat = true; + } + overviewChannelData = new OverviewChannelData(stats); maxDateOverview = stats.period.max_date * 1000L; minDateOverview = stats.period.min_date * 1000L; @@ -239,6 +244,13 @@ public class StatisticActivity extends BaseFragment implements NotificationCente chartsViewData[6] = createViewData(stats.top_hours_graph, LocaleController.getString("TopHoursChartTitle", R.string.TopHoursChartTitle), 0); chartsViewData[7] = createViewData(stats.weekdays_graph, LocaleController.getString("TopDaysOfWeekChartTitle", R.string.TopDaysOfWeekChartTitle), 4); + if (chartsViewData[6] != null) { + chartsViewData[6].useHourFormat = true; + } + if (chartsViewData[7] != null) { + chartsViewData[7].useWeekFormat = true; + } + overviewChatData = new OverviewChatData(stats); maxDateOverview = stats.period.max_date * 1000L; minDateOverview = stats.period.min_date * 1000L; @@ -447,13 +459,8 @@ public class StatisticActivity extends BaseFragment implements NotificationCente recyclerListView.setOnItemClickListener((view, position) -> { if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; - - Bundle bundle = new Bundle(); - bundle.putInt("chat_id", chat.id); - bundle.putInt("message_id", messageObject.getId()); - bundle.putBoolean("need_remove_previous_same_chat_activity", false); - ChatActivity chatActivity = new ChatActivity(bundle); - presentFragment(chatActivity, false); + MessageStatisticActivity activity = new MessageStatisticActivity(messageObject); + presentFragment(activity); } else if (position >= adapter.topAdminsStartRow && position <= adapter.topAdminsEndRow) { int i = position - adapter.topAdminsStartRow; topAdmins.get(i).onClick(this); @@ -478,7 +485,40 @@ public class StatisticActivity extends BaseFragment implements NotificationCente }); recyclerListView.setOnItemLongClickListener((view, position) -> { - if (position >= adapter.topAdminsStartRow && position <= adapter.topAdminsEndRow) { + if (position >= adapter.recentPostsStartRow && position <= adapter.recentPostsEndRow) { + MessageObject messageObject = recentPostsLoaded.get(position - adapter.recentPostsStartRow).message; + + final ArrayList items = new ArrayList<>(); + final ArrayList actions = new ArrayList<>(); + final ArrayList icons = new ArrayList<>(); + + items.add(LocaleController.getString("ViewMessageStatistic", R.string.ViewMessageStatistic)); + actions.add(0); + icons.add(R.drawable.msg_stats); + + items.add(LocaleController.getString("ViewMessage", R.string.ViewMessage)); + actions.add(1); + icons.add(R.drawable.menu_chats); + + + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { + if (i == 0) { + MessageStatisticActivity activity = new MessageStatisticActivity(messageObject); + presentFragment(activity); + } else if (i == 1) { + Bundle bundle = new Bundle(); + bundle.putInt("chat_id", chat.id); + bundle.putInt("message_id", messageObject.getId()); + bundle.putBoolean("need_remove_previous_same_chat_activity", false); + ChatActivity chatActivity = new ChatActivity(bundle); + presentFragment(chatActivity, false); + } + }); + + showDialog(builder.create()); + + } else if (position >= adapter.topAdminsStartRow && position <= adapter.topAdminsEndRow) { int i = position - adapter.topAdminsStartRow; topAdmins.get(i).onLongClick(chat, this, progressDialog); return true; @@ -537,11 +577,12 @@ public class StatisticActivity extends BaseFragment implements NotificationCente return fragmentView; } - private ChartViewData createViewData(TLRPC.StatsGraph graph, String title, int graphType, boolean isLanguages) { + public static ChartViewData createViewData(TLRPC.StatsGraph graph, String title, int graphType, boolean isLanguages) { if (graph == null || graph instanceof TLRPC.TL_statsGraphError) { return null; } ChartViewData viewData = new ChartViewData(title, graphType); + viewData.isLanguages = isLanguages; if (graph instanceof TLRPC.TL_statsGraph) { String json = ((TLRPC.TL_statsGraph) graph).json.data; try { @@ -566,11 +607,11 @@ public class StatisticActivity extends BaseFragment implements NotificationCente return viewData; } - private ChartViewData createViewData(TLRPC.StatsGraph graph, String title, int graphType) { + private static ChartViewData createViewData(TLRPC.StatsGraph graph, String title, int graphType) { return createViewData(graph, title, graphType, false); } - private static ChartData createChartData(JSONObject jsonObject, int graphType, boolean isLanguages) throws JSONException { + public static ChartData createChartData(JSONObject jsonObject, int graphType, boolean isLanguages) throws JSONException { if (graphType == 0) { return new ChartData(jsonObject); } else if (graphType == 1) { @@ -703,7 +744,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v; if (viewType >= 0 && viewType <= 4) { - v = new ChartCell(parent.getContext(), viewType) { + v = new ChartCell(parent.getContext(), viewType, sharedUi) { @Override protected void onDraw(Canvas canvas) { if (getTranslationY() != 0) { @@ -1058,7 +1099,97 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } } - public class ChartCell extends FrameLayout { + private class ChartCell extends BaseChartCell { + + public ChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi) { + super(context, type, sharedUi); + } + + @Override + public void zoomCanceled() { + cancelZoom(); + } + + @Override + public void onZoomed() { + if (data.activeZoom > 0) { + return; + } + performClick(); + if (!chartView.legendSignatureView.canGoZoom) { + return; + } + final long x = chartView.getSelectedDate(); + if (chartType == 4) { + data.childChartData = new StackLinearChartData(data.chartData, x); + zoomChart(false); + return; + } + + if (data.zoomToken == null) { + return; + } + + cancelZoom(); + final String cacheKey = data.zoomToken + "_" + x; + ChartData dataFromCache = childDataCache.get(cacheKey); + if (dataFromCache != null) { + data.childChartData = dataFromCache; + zoomChart(false); + return; + } + + TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); + request.token = data.zoomToken; + if (x != 0) { + request.x = x; + request.flags |= 1; + } + ZoomCancelable finalCancelabel; + lastCancelable = finalCancelabel = new ZoomCancelable(); + finalCancelabel.adapterPosition = recyclerListView.getChildAdapterPosition(ChartCell.this); + + chartView.legendSignatureView.showProgress(true, false); + + int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { + ChartData childData = null; + if (response instanceof TLRPC.TL_statsGraph) { + String json = ((TLRPC.TL_statsGraph) response).json.data; + try { + childData = createChartData(new JSONObject(json), data.graphType, data == languagesData); + } catch (JSONException e) { + e.printStackTrace(); + } + } else if (response instanceof TLRPC.TL_statsGraphError) { + Toast.makeText(getContext(), ((TLRPC.TL_statsGraphError) response).error, Toast.LENGTH_LONG).show(); + } + + ChartData finalChildData = childData; + AndroidUtilities.runOnUIThread(() -> { + if (finalChildData != null) { + childDataCache.put(cacheKey, finalChildData); + } + if (finalChildData != null && !finalCancelabel.canceled && finalCancelabel.adapterPosition >= 0) { + View view = layoutManager.findViewByPosition(finalCancelabel.adapterPosition); + if (view instanceof ChartCell) { + data.childChartData = finalChildData; + ((ChartCell) view).chartView.legendSignatureView.showProgress(false, false); + ((ChartCell) view).zoomChart(false); + } + } + cancelZoom(); + }); + }, null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); + ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); + } + + @Override + public void loadData(ChartViewData viewData) { + viewData.load(currentAccount, classGuid, chat.stats_dc, recyclerListView, adapter, diffUtilsCallback); + } + } + + public static abstract class BaseChartCell extends FrameLayout { BaseChartView chartView; BaseChartView zoomedChartView; ChartHeaderView chartHeaderView; @@ -1073,7 +1204,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente int chartType; @SuppressLint("ClickableViewAccessibility") - public ChartCell(@NonNull Context context, int type) { + public BaseChartCell(@NonNull Context context, int type, BaseChartView.SharedUiComponents sharedUi) { super(context); setWillNotDraw(false); chartType = type; @@ -1167,83 +1298,14 @@ public class StatisticActivity extends BaseFragment implements NotificationCente chartView.setDateSelectionListener(date -> { - cancelZoom(); + zoomCanceled(); chartView.legendSignatureView.showProgress(false, false); }); chartView.legendSignatureView.showProgress(false, false); chartView.legendSignatureView.setOnTouchListener(new RecyclerListView.FoucsableOnTouchListener()); chartView.legendSignatureView.setOnClickListener(v -> { - if (data.activeZoom > 0) { - return; - } - performClick(); - if (!chartView.legendSignatureView.canGoZoom) { - return; - } - final long x = chartView.getSelectedDate(); - if (chartType == 4) { - data.childChartData = new StackLinearChartData(data.chartData, x); - zoomChart(false); - return; - } - - if (data.zoomToken == null) { - return; - } - - cancelZoom(); - final String cacheKey = data.zoomToken + "_" + x; - ChartData dataFromCache = childDataCache.get(cacheKey); - if (dataFromCache != null) { - data.childChartData = dataFromCache; - zoomChart(false); - return; - } - - TLRPC.TL_stats_loadAsyncGraph request = new TLRPC.TL_stats_loadAsyncGraph(); - request.token = data.zoomToken; - if (x != 0) { - request.x = x; - request.flags |= 1; - } - ZoomCancelable finalCancelabel; - lastCancelable = finalCancelabel = new ZoomCancelable(); - finalCancelabel.adapterPosition = recyclerListView.getChildAdapterPosition(ChartCell.this); - - chartView.legendSignatureView.showProgress(true, false); - - int reqId = ConnectionsManager.getInstance(currentAccount).sendRequest(request, (response, error) -> { - ChartData childData = null; - if (response instanceof TLRPC.TL_statsGraph) { - String json = ((TLRPC.TL_statsGraph) response).json.data; - try { - childData = createChartData(new JSONObject(json), data.graphType, data == languagesData); - } catch (JSONException e) { - e.printStackTrace(); - } - } else if (response instanceof TLRPC.TL_statsGraphError) { - Toast.makeText(context, ((TLRPC.TL_statsGraphError) response).error, Toast.LENGTH_LONG).show(); - } - - ChartData finalChildData = childData; - AndroidUtilities.runOnUIThread(() -> { - if (finalChildData != null) { - childDataCache.put(cacheKey, finalChildData); - } - if (finalChildData != null && !finalCancelabel.canceled && finalCancelabel.adapterPosition >= 0) { - View view = layoutManager.findViewByPosition(finalCancelabel.adapterPosition); - if (view instanceof ChartCell) { - data.childChartData = finalChildData; - ((ChartCell) view).chartView.legendSignatureView.showProgress(false, false); - ((ChartCell) view).zoomChart(false); - } - } - cancelZoom(); - }); - }, null, null, 0, chat.stats_dc, ConnectionsManager.ConnectionTypeGeneric, true); - ConnectionsManager.getInstance(currentAccount).bindRequestToGuid(reqId, classGuid); - + onZoomed(); }); zoomedChartView.legendSignatureView.setOnClickListener(v -> { zoomedChartView.animateLegend(false); @@ -1266,7 +1328,13 @@ public class StatisticActivity extends BaseFragment implements NotificationCente addView(linearLayout); } - private void zoomChart(boolean skipTransition) { + public abstract void onZoomed(); + + public abstract void zoomCanceled(); + + abstract void loadData(ChartViewData viewData); + + public void zoomChart(boolean skipTransition) { long d = chartView.getSelectedDate(); ChartData childData = data.childChartData; // if (childData == null) return; @@ -1503,13 +1571,13 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } errorTextView.setVisibility(View.GONE); - chartView.legendSignatureView.isTopHourChart = viewData == topHoursData; - chartHeaderView.showDate(viewData != topHoursData); + chartView.legendSignatureView.isTopHourChart = viewData.useHourFormat; + chartHeaderView.showDate(!viewData.useHourFormat); if (viewData.chartData == null && viewData.token != null) { progressView.setAlpha(1f); progressView.setVisibility(View.VISIBLE); - viewData.load(currentAccount, classGuid, chat.stats_dc, recyclerListView, adapter, diffUtilsCallback); + loadData(viewData); chartView.setData(null); return; } else if (!enterTransition) { @@ -1517,8 +1585,8 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } chartView.setData(viewData.chartData); - chartHeaderView.setUseWeekInterval(viewData == topDayOfWeeksData); - chartView.legendSignatureView.setUseWeek(viewData == topDayOfWeeksData); + chartHeaderView.setUseWeekInterval(viewData.useWeekFormat); + chartView.legendSignatureView.setUseWeek(viewData.useWeekFormat); chartView.legendSignatureView.zoomEnabled = !(data.zoomToken == null && chartType != 4); zoomedChartView.legendSignatureView.zoomEnabled = false; @@ -1629,7 +1697,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente break; } } - cancelZoom(); + zoomCanceled(); if (allDisabled) { checkBox.denied(); return; @@ -1650,7 +1718,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente if (!checkBox.enabled) { return false; } - cancelZoom(); + zoomCanceled(); int n = checkBoxes.size(); for (int i = 0; i < n; i++) { checkBoxes.get(i).checkBox.setChecked(false); @@ -1693,12 +1761,12 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } - private static class ZoomCancelable { + public static class ZoomCancelable { int adapterPosition; boolean canceled; } - private class ChartViewData { + public static class ChartViewData { public boolean isError; public String errorMessage; @@ -1714,6 +1782,9 @@ public class StatisticActivity extends BaseFragment implements NotificationCente boolean loading; boolean isEmpty; + boolean isLanguages; + boolean useHourFormat; + boolean useWeekFormat; public ChartViewData(String title, int grahType) { this.title = title; @@ -1732,7 +1803,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente if (response instanceof TLRPC.TL_statsGraph) { String json = ((TLRPC.TL_statsGraph) response).json.data; try { - chartData = createChartData(new JSONObject(json), graphType, this == languagesData); + chartData = createChartData(new JSONObject(json), graphType, isLanguages); zoomToken = ((TLRPC.TL_statsGraph) response).zoom_token; if (graphType == 4 && chartData.x != null && chartData.x.length > 0) { long x = chartData.x[chartData.x.length - 1]; @@ -1846,19 +1917,15 @@ public class StatisticActivity extends BaseFragment implements NotificationCente private void recolorRecyclerItem(View child) { if (child instanceof ChartCell) { ((ChartCell) child).recolor(); - } - - if (child instanceof ShadowSectionCell) { + } else if (child instanceof ShadowSectionCell) { Drawable shadowDrawable = Theme.getThemedDrawable(ApplicationLoader.applicationContext, R.drawable.greydivider, Theme.key_windowBackgroundGrayShadow); Drawable background = new ColorDrawable(Theme.getColor(Theme.key_windowBackgroundGray)); CombinedDrawable combinedDrawable = new CombinedDrawable(background, shadowDrawable, 0, 0); combinedDrawable.setFullsize(true); child.setBackground(combinedDrawable); - } - if (child instanceof ChartHeaderView) { + } else if (child instanceof ChartHeaderView) { ((ChartHeaderView) child).recolor(); - } - if (child instanceof OverviewCell) { + } else if (child instanceof OverviewCell) { ((OverviewCell) child).updateColors(); } } @@ -2082,7 +2149,6 @@ public class StatisticActivity extends BaseFragment implements NotificationCente arrayList.add(new ThemeDescription(recyclerListView, ThemeDescription.FLAG_CHECKTAG, new Class[]{ManageChatTextCell.class}, new String[]{"textView"}, null, null, null, Theme.key_windowBackgroundWhiteRedText5)); arrayList.add(new ThemeDescription(recyclerListView, ThemeDescription.FLAG_CELLBACKGROUNDCOLOR, new Class[]{ManageChatUserCell.class, ManageChatTextCell.class, HeaderCell.class, TextView.class, PeopleNearbyActivity.HintInnerCell.class}, null, null, null, Theme.key_windowBackgroundWhite)); - if (isMegagroup) { for (int i = 0; i < 6; i++) { ChartViewData chartViewData; @@ -2130,7 +2196,7 @@ public class StatisticActivity extends BaseFragment implements NotificationCente return arrayList; } - private void putColorFromData(ChartViewData chartViewData, ArrayList arrayList, ThemeDescription.ThemeDescriptionDelegate themeDelegate) { + public static void putColorFromData(ChartViewData chartViewData, ArrayList arrayList, ThemeDescription.ThemeDescriptionDelegate themeDelegate) { if (chartViewData != null && chartViewData.chartData != null) { for (ChartData.Line l : chartViewData.chartData.lines) { if (l.colorKey != null) { @@ -2390,7 +2456,6 @@ public class StatisticActivity extends BaseFragment implements NotificationCente secondary[i].setTextColor(Theme.getColor(colorKey)); } } - } } @@ -2575,11 +2640,18 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } boolean isAdmin = false; - if (currentUser != null && currentParticipant != null && currentUser.channelParticipant.admin_rights != null && currentUser.channelParticipant.admin_rights.add_admins) { - isAdmin = currentParticipant.channelParticipant.admin_rights == null; - items.add(isAdmin ? LocaleController.getString("SetAsAdmin", R.string.SetAsAdmin) : LocaleController.getString("EditAdminRights", R.string.EditAdminRights)); - icons.add(isAdmin ? R.drawable.actions_addadmin : R.drawable.actions_permissions); - actions.add(0); + if (currentUser != null && currentParticipant != null && currentUser.user_id != currentParticipant.user_id) { + TLRPC.ChannelParticipant channelParticipant = currentParticipant.channelParticipant; + boolean canEditAdmin = currentUser.channelParticipant.admin_rights != null && currentUser.channelParticipant.admin_rights.add_admins; + if (canEditAdmin && (channelParticipant instanceof TLRPC.TL_channelParticipantCreator || channelParticipant instanceof TLRPC.TL_channelParticipantAdmin && !channelParticipant.can_edit)) { + canEditAdmin = false; + } + if (canEditAdmin) { + isAdmin = channelParticipant.admin_rights == null; + items.add(isAdmin ? LocaleController.getString("SetAsAdmin", R.string.SetAsAdmin) : LocaleController.getString("EditAdminRights", R.string.EditAdminRights)); + icons.add(isAdmin ? R.drawable.actions_addadmin : R.drawable.actions_permissions); + actions.add(0); + } } AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); @@ -2587,7 +2659,15 @@ public class StatisticActivity extends BaseFragment implements NotificationCente boolean finalIsAdmin = isAdmin; builder.setItems(items.toArray(new CharSequence[actions.size()]), AndroidUtilities.toIntArray(icons), (dialogInterface, i) -> { if (actions.get(i) == 0) { - ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin); + boolean[] needShowBulletin = new boolean[1]; + ChatRightsEditActivity newFragment = new ChatRightsEditActivity(user.id, chat.id, finalCurrentParticipant.channelParticipant.admin_rights, null, finalCurrentParticipant.channelParticipant.banned_rights, finalCurrentParticipant.channelParticipant.rank, ChatRightsEditActivity.TYPE_ADMIN, true, finalIsAdmin) { + @Override + protected void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (!isOpen && backward && needShowBulletin[0] && BulletinFactory.canShowBulletin(fragment)) { + BulletinFactory.createPromoteToAdminBulletin(fragment, user.first_name).show(); + } + } + }; newFragment.setDelegate(new ChatRightsEditActivity.ChatRightsEditActivityDelegate() { @Override public void didSetRights(int rights, TLRPC.TL_chatAdminRights rightsAdmin, TLRPC.TL_chatBannedRights rightsBanned, String rank) { @@ -2597,6 +2677,9 @@ public class StatisticActivity extends BaseFragment implements NotificationCente } else { finalCurrentParticipant.channelParticipant.admin_rights = rightsAdmin; finalCurrentParticipant.channelParticipant.rank = rank; + if (finalIsAdmin) { + needShowBulletin[0] = true; + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ViewPagerFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/ViewPagerFixed.java index 20280a0c4..0ef46b4fa 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ViewPagerFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ViewPagerFixed.java @@ -32,6 +32,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.graphics.ColorUtils; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; @@ -272,10 +273,6 @@ public class ViewPagerFixed extends FrameLayout { velocityTracker.addMovement(ev); } if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && checkTabsAnimationInProgress()) { - View child = findScrollingChild(this, ev.getX(), ev.getY()); - if (child != null && (child.canScrollHorizontally(1) || child.canScrollHorizontally(-1))) { - return false; - } startedTracking = true; startedTrackingPointerId = ev.getPointerId(0); startedTrackingX = (int) ev.getX(); @@ -302,6 +299,13 @@ public class ViewPagerFixed extends FrameLayout { } else if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) { additionalOffset = 0; } + + if (!startedTracking && ev != null) { + View child = findScrollingChild(this, ev.getX(), ev.getY()); + if (child != null && (child.canScrollHorizontally(1) || child.canScrollHorizontally(-1))) { + return false; + } + } if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking) { startedTrackingPointerId = ev.getPointerId(0); maybeStartTracking = true; @@ -624,6 +628,7 @@ public class ViewPagerFixed extends FrameLayout { public void setTab(Tab tab, int position) { currentTab = tab; currentPosition = position; + setContentDescription(tab.title); requestLayout(); } @@ -938,6 +943,14 @@ public class ViewPagerFixed extends FrameLayout { public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { return super.scrollHorizontallyBy(dx, recycler, state); } + + @Override + public void onInitializeAccessibilityNodeInfo(@NonNull RecyclerView.Recycler recycler, @NonNull RecyclerView.State state, @NonNull AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(recycler, state, info); + if (isInHiddenMode) { + info.setVisibleToUser(false); + } + } }); listView.setPadding(AndroidUtilities.dp(7), 0, AndroidUtilities.dp(7), 0); listView.setClipToPadding(false); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/MessageHelper.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/MessageHelper.java index 8238bf28f..3569fc586 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/MessageHelper.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/MessageHelper.java @@ -3,6 +3,7 @@ package tw.nekomimi.nekogram; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.BaseController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.tgnet.ConnectionsManager; @@ -156,7 +157,7 @@ public class MessageHelper extends BaseController { req.q = ""; req.offset_id = offset_id; if (user != null) { - req.from_id = getMessagesController().getInputUser(user); + req.from_id = MessagesController.getInputPeer(user); req.flags |= 1; } req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); diff --git a/TMessagesProj/src/main/res/drawable-hdpi/blockpanel_shadow.png b/TMessagesProj/src/main/res/drawable-hdpi/blockpanel_shadow.png new file mode 100644 index 000000000..83faa725d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/blockpanel_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_background_image.9.png b/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_background_image.9.png new file mode 100644 index 000000000..7091d810a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_no_shadow_background_image.9.png b/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_no_shadow_background_image.9.png new file mode 100644 index 000000000..4f9bc6ba7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/googlepay_button_no_shadow_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/map_pin_arrow.png b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_arrow.png new file mode 100644 index 000000000..a5cd5b17e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/map_pin_circle.png b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_circle.png new file mode 100644 index 000000000..0216074ab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/map_pin_cone2.png b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_cone2.png new file mode 100644 index 000000000..f7f1fe1f5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_cone2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/map_pin_photo.png b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_photo.png new file mode 100644 index 000000000..a8f576924 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/map_pin_photo.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_bookmarks_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_bookmarks_hw.png new file mode 100644 index 000000000..409ef0fa9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_bookmarks_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_broadcast_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_broadcast_hw.png new file mode 100644 index 000000000..dd2f30339 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_broadcast_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_calls_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_calls_hw.png new file mode 100644 index 000000000..f6f3017dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_calls_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_contacts_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_contacts_hw.png new file mode 100644 index 000000000..b3f223a76 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_contacts_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_groups_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_groups_hw.png new file mode 100644 index 000000000..8cf9cb2be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_groups_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_help_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_help_hw.png new file mode 100644 index 000000000..8a04a4d87 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_help_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_invite_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_invite_hw.png new file mode 100644 index 000000000..d03a13e2e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_invite_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_pinnedlist.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_pinnedlist.png new file mode 100644 index 000000000..0b32c64af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_pinnedlist.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_secret_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_secret_hw.png new file mode 100644 index 000000000..cb49bf691 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_secret_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_settings_hw.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_settings_hw.png new file mode 100644 index 000000000..e2a9ccb6b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_settings_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert.png new file mode 100644 index 000000000..f5999728a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert2.png new file mode 100644 index 000000000..ff4f2155d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_location_alert2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_pin_mini.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_pin_mini.png new file mode 100644 index 000000000..426c3b7f3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_pin_mini.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_stats.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_stats.png index ae3f60f92..32128c3be 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/msg_stats.png and b/TMessagesProj/src/main/res/drawable-hdpi/msg_stats.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/blockpanel_shadow.png b/TMessagesProj/src/main/res/drawable-mdpi/blockpanel_shadow.png new file mode 100644 index 000000000..e5ef73a01 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/blockpanel_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_background_image.9.png b/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_background_image.9.png new file mode 100644 index 000000000..a60464a36 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_no_shadow_background_image.9.png b/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_no_shadow_background_image.9.png new file mode 100644 index 000000000..d0be7ed2d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/googlepay_button_no_shadow_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/map_pin_arrow.png b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_arrow.png new file mode 100644 index 000000000..c9e79c145 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/map_pin_circle.png b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_circle.png new file mode 100644 index 000000000..8791bd765 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/map_pin_cone2.png b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_cone2.png new file mode 100644 index 000000000..2ad32c3a4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_cone2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/map_pin_photo.png b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_photo.png new file mode 100644 index 000000000..5e58ff0f8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/map_pin_photo.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_bookmarks_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_bookmarks_hw.png new file mode 100644 index 000000000..cd13817ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_bookmarks_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_broadcast_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_broadcast_hw.png new file mode 100644 index 000000000..d602c9dbd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_broadcast_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_calls_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_calls_hw.png new file mode 100644 index 000000000..e32c14e13 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_calls_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_contacts_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_contacts_hw.png new file mode 100644 index 000000000..1aab19c56 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_contacts_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_groups_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_groups_hw.png new file mode 100644 index 000000000..f7ce13365 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_groups_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_help_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_help_hw.png new file mode 100644 index 000000000..f6dfc66b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_help_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_invite_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_invite_hw.png new file mode 100644 index 000000000..787c15043 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_invite_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_pinnedlist.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_pinnedlist.png new file mode 100644 index 000000000..57b6bf7b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_pinnedlist.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_secret_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_secret_hw.png new file mode 100644 index 000000000..c69a4b061 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_secret_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_settings_hw.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_settings_hw.png new file mode 100644 index 000000000..e72b3f3e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_settings_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert.png new file mode 100644 index 000000000..1420d474f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert2.png new file mode 100644 index 000000000..8b97c2d96 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_location_alert2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_pin_mini.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_pin_mini.png new file mode 100644 index 000000000..d4fd000bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_pin_mini.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_stats.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_stats.png index 68cc22fba..a684b8632 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/msg_stats.png and b/TMessagesProj/src/main/res/drawable-mdpi/msg_stats.png differ diff --git a/TMessagesProj/src/main/res/drawable-v21/googlepay_button_background.xml b/TMessagesProj/src/main/res/drawable-v21/googlepay_button_background.xml new file mode 100644 index 000000000..4873ef242 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/googlepay_button_background.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/TMessagesProj/src/main/res/drawable-v21/googlepay_button_no_shadow_background.xml b/TMessagesProj/src/main/res/drawable-v21/googlepay_button_no_shadow_background.xml new file mode 100644 index 000000000..d44e9eb62 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/googlepay_button_no_shadow_background.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel_shadow.png b/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel_shadow.png new file mode 100644 index 000000000..5ffe3c35f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png new file mode 100644 index 000000000..40f767d53 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_no_shadow_background_image.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_no_shadow_background_image.9.png new file mode 100644 index 000000000..969cc52a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/googlepay_button_no_shadow_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_arrow.png b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_arrow.png new file mode 100644 index 000000000..1e3326abc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_circle.png b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_circle.png new file mode 100644 index 000000000..5bb002ab5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_cone2.png b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_cone2.png new file mode 100644 index 000000000..68ec2ddb4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_cone2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_photo.png b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_photo.png new file mode 100644 index 000000000..03fc81436 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/map_pin_photo.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_bookmarks_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_bookmarks_hw.png new file mode 100644 index 000000000..fe9795acd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_bookmarks_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_broadcast_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_broadcast_hw.png new file mode 100644 index 000000000..b075d5396 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_broadcast_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_calls_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_calls_hw.png new file mode 100644 index 000000000..4617f03ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_calls_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_contacts_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_contacts_hw.png new file mode 100644 index 000000000..dd6379123 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_contacts_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_groups_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_groups_hw.png new file mode 100644 index 000000000..0b9863870 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_groups_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_help_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_help_hw.png new file mode 100644 index 000000000..4c1af3018 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_help_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_invite_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_invite_hw.png new file mode 100644 index 000000000..4ce59ea71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_invite_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_pinnedlist.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_pinnedlist.png new file mode 100644 index 000000000..96149c0f6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_pinnedlist.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_secret_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_secret_hw.png new file mode 100644 index 000000000..65bddf019 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_secret_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_settings_hw.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_settings_hw.png new file mode 100644 index 000000000..b8f13f341 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_settings_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert.png new file mode 100644 index 000000000..8f6181fac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert2.png new file mode 100644 index 000000000..2c556f1b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_location_alert2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_pin_mini.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_pin_mini.png new file mode 100644 index 000000000..14051dfa7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_pin_mini.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stats.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stats.png index 13cec400c..2f230ea39 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/msg_stats.png and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_stats.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel_shadow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel_shadow.png new file mode 100644 index 000000000..9da559d19 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel_shadow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png new file mode 100644 index 000000000..91035e2a4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_no_shadow_background_image.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_no_shadow_background_image.9.png new file mode 100644 index 000000000..dda66dfd0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/googlepay_button_no_shadow_background_image.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_arrow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_arrow.png new file mode 100644 index 000000000..53a539fef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_circle.png b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_circle.png new file mode 100644 index 000000000..810dbed01 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_cone2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_cone2.png new file mode 100644 index 000000000..21125f8df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_cone2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_photo.png b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_photo.png new file mode 100644 index 000000000..3b2d2d622 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/map_pin_photo.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_bookmarks_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_bookmarks_hw.png new file mode 100644 index 000000000..97ff71c3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_bookmarks_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_broadcast_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_broadcast_hw.png new file mode 100644 index 000000000..b05f14bce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_broadcast_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_calls_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_calls_hw.png new file mode 100644 index 000000000..0e3feaf9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_calls_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_contacts_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_contacts_hw.png new file mode 100644 index 000000000..1823841c1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_contacts_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_groups_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_groups_hw.png new file mode 100644 index 000000000..5167dfccc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_groups_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_help_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_help_hw.png new file mode 100644 index 000000000..3d2250966 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_help_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_invite_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_invite_hw.png new file mode 100644 index 000000000..d41dac440 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_invite_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_pinnedlist.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_pinnedlist.png new file mode 100644 index 000000000..9ead51302 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_pinnedlist.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_secret_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_secret_hw.png new file mode 100644 index 000000000..8572f1e03 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_secret_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_settings_hw.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_settings_hw.png new file mode 100644 index 000000000..82f454843 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_settings_hw.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert.png new file mode 100644 index 000000000..2678d0d75 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert2.png new file mode 100644 index 000000000..f72a6e1d6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_location_alert2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_pin_mini.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_pin_mini.png new file mode 100644 index 000000000..c43137632 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_pin_mini.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stats.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stats.png index 4e0581776..6b9a52a8c 100644 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stats.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_stats.png differ diff --git a/TMessagesProj/src/main/res/drawable/buy_with_googlepay_button_content.xml b/TMessagesProj/src/main/res/drawable/buy_with_googlepay_button_content.xml new file mode 100644 index 000000000..a893cd0ca --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/buy_with_googlepay_button_content.xml @@ -0,0 +1,54 @@ + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/googlepay_button_background.xml b/TMessagesProj/src/main/res/drawable/googlepay_button_background.xml new file mode 100644 index 000000000..b81005b06 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/googlepay_button_background.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/TMessagesProj/src/main/res/drawable/googlepay_button_content.xml b/TMessagesProj/src/main/res/drawable/googlepay_button_content.xml new file mode 100644 index 000000000..b2cdb1d52 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/googlepay_button_content.xml @@ -0,0 +1,48 @@ + + + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/googlepay_button_no_shadow_background.xml b/TMessagesProj/src/main/res/drawable/googlepay_button_no_shadow_background.xml new file mode 100644 index 000000000..9543c4bcb --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/googlepay_button_no_shadow_background.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/TMessagesProj/src/main/res/drawable/googlepay_button_overlay.xml b/TMessagesProj/src/main/res/drawable/googlepay_button_overlay.xml new file mode 100644 index 000000000..70c7a9227 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/googlepay_button_overlay.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + diff --git a/TMessagesProj/src/main/res/raw/ic_admin.json b/TMessagesProj/src/main/res/raw/ic_admin.json new file mode 100644 index 000000000..a5563ecfb --- /dev/null +++ b/TMessagesProj/src/main/res/raw/ic_admin.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":60,"ip":0,"op":120,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":27,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":37,"s":[8]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":46,"s":[-6]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":54,"s":[3]},{"t":60,"s":[0]}],"ix":10},"p":{"a":0,"k":[248,442,0],"ix":2},"a":{"a":0,"k":[50,100,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shield","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":4,"s":[-22]},{"i":{"x":[0.3],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":16,"s":[8]},{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[-15]},{"t":41,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[-70.6,6.05,0],"to":[42.6,-67.05,0],"ti":[0,0,0]},{"i":{"x":0.828,"y":0.044},"o":{"x":0.6,"y":0},"t":13,"s":[97.399,-129.949,0],"to":[-19.379,6.221,0],"ti":[0,0,0]},{"i":{"x":0.406,"y":1},"o":{"x":0.246,"y":0.374},"t":21,"s":[63.182,-110.868,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.573,"y":0.64},"o":{"x":0.369,"y":0},"t":27,"s":[-15.6,-36.95,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.566,"y":1},"o":{"x":0.251,"y":0.573},"t":33,"s":[37.19,-71.312,0],"to":[0,0,0],"ti":[0,0,0]},{"t":38,"s":[53.4,-81.95,0]}],"ix":2},"a":{"a":0,"k":[-4.6,4.05,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"t":7,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0.054,-0.115],[0,0],[0,0],[0.048,-0.003],[0.138,-0.008],[-0.012,-0.101],[0,0],[0,0],[0.023,-0.088],[0,0],[-0.079,0.063],[0,0],[0,0],[-0.014,-0.042],[-0.03,-0.034],[-0.017,0.128],[0,0],[0,0],[-0.043,0.054],[0,0],[0,0],[0.051,0.018],[0,0],[0,0],[-0.006,0.095],[0,0],[0,0]],"o":[[0,0],[0,0],[-0.041,0.082],[0,0],[-0.058,0.001],[0,0],[0,0],[0.006,0.049],[0,0],[-0.077,0.24],[0,0],[0,0],[0.047,-0.03],[0.008,0.024],[0.041,0.046],[0,0],[0,0],[0.023,-0.088],[0,0],[0,0],[0.092,-0.12],[0,0],[0,0],[-0.036,-0.013],[0,0],[0,0],[0.034,-0.355]],"v":[[197.681,26.778],[197.681,26.778],[196.951,28.298],[196.816,28.443],[196.076,28.316],[195.983,28.583],[195.983,28.583],[196.174,29.997],[196.152,30.23],[195.646,31.782],[195.713,32.046],[195.713,32.046],[196.449,31.536],[196.574,31.58],[196.975,32.531],[197.11,32.346],[197.11,32.346],[197.427,30.774],[197.52,30.567],[197.52,30.567],[198.395,29.528],[198.452,29.165],[198.452,29.165],[197.764,28.825],[197.71,28.662],[197.71,28.662],[197.837,26.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.622,"y":0},"t":13,"s":[{"i":[[1.53,-2.811],[0,0],[0,0],[1.348,-0.085],[3.904,-0.201],[-0.353,-2.474],[0,0],[0,0],[0.66,-2.165],[0,0],[-2.254,1.536],[0,0],[0,0],[-0.39,-1.035],[-0.85,-0.821],[-0.491,3.133],[0,0],[0,0],[-1.232,1.325],[0,0],[0,0],[1.454,0.443],[0,0],[0,0],[-0.17,2.315],[0,0],[0,0]],"o":[[0,0],[0,0],[-1.15,2.016],[0,0],[-1.653,0.014],[0,0],[0,0],[0.171,1.197],[0,0],[-2.172,5.865],[0,0],[0,0],[1.333,-0.739],[0.221,0.587],[1.172,1.134],[0,0],[0,0],[0.66,-2.165],[0,0],[0,0],[2.598,-2.936],[0,0],[0,0],[-1.013,-0.309],[0,0],[0,0],[0.973,-8.699]],"v":[[196.148,-38.703],[196.148,-38.703],[175.448,-1.5],[171.612,2.063],[150.62,-1.056],[147.998,5.475],[147.998,5.475],[153.407,40.102],[152.781,45.789],[138.446,83.787],[140.336,90.241],[140.336,90.241],[161.217,77.752],[164.746,78.828],[176.121,102.113],[179.957,97.588],[179.957,97.588],[188.94,59.103],[191.592,54.034],[191.592,54.034],[209.206,25.848],[210.812,16.948],[210.812,16.948],[198.515,11.41],[196.978,7.43],[196.978,7.43],[200.575,-35.063]],"c":true}]},{"i":{"x":0.472,"y":1},"o":{"x":0.167,"y":0.167},"t":21,"s":[{"i":[[1.543,-3.678],[0,0],[0,0],[2.343,-0.416],[6.806,-1.149],[-1.641,-2.84],[0,0],[0,0],[0.274,-2.712],[0,0],[-3.346,2.341],[0,0],[0,0],[-1.114,-1.132],[-1.837,-0.772],[0.423,3.815],[0,0],[0,0],[-1.628,1.853],[0,0],[0,0],[2.749,0.184],[0,0],[0,0],[0.652,2.774],[0,0],[0,0]],"o":[[0,0],[0,0],[-1.201,2.65],[0,0],[-2.912,0.402],[0,0],[0,0],[0.794,1.374],[0,0],[-1.42,7.435],[0,0],[0,0],[2.048,-1.184],[0.631,0.641],[2.535,1.065],[0,0],[0,0],[0.274,-2.712],[0,0],[0,0],[3.376,-4.075],[0,0],[0,0],[-1.915,-0.128],[0,0],[0,0],[-1.861,-10.503]],"v":[[90.227,-80.159],[90.227,-80.159],[69.004,-31.379],[63.699,-26.274],[25.372,-25.056],[23.432,-16.728],[23.432,-16.728],[47.224,22.913],[48.458,29.777],[38.795,78.01],[44.785,85.193],[44.785,85.193],[76.495,65.562],[83.166,66.009],[112.82,90.859],[117.727,84.617],[117.727,84.617],[117.745,37.059],[120.341,30.451],[120.341,30.451],[150.694,-6.515],[149.867,-17.403],[149.867,-17.403],[115.021,-21.516],[110.671,-25.858],[110.671,-25.858],[99.536,-76.893]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":27,"s":[{"i":[[1.521,-5.435],[0,0],[0,0],[3.699,-1.08],[10.762,-3.057],[-3.433,-3.587],[0,0],[0,0],[-0.284,-3.821],[0,0],[-4.813,3.967],[0,0],[0,0],[-2.116,-1.33],[-3.196,-0.676],[1.714,5.202],[0,0],[0,0],[-2.15,2.92],[0,0],[0,0],[4.521,-0.335],[0,0],[0,0],[1.807,3.708],[0,0],[0,0]],"o":[[0,0],[0,0],[-1.24,3.934],[0,0],[-4.629,1.184],[0,0],[0,0],[1.661,1.736],[0,0],[-0.31,10.62],[0,0],[0,0],[3.012,-2.083],[1.2,0.754],[4.411,0.933],[0,0],[0,0],[-0.284,-3.821],[0,0],[0,0],[4.396,-6.378],[0,0],[0,0],[-3.149,0.234],[0,0],[0,0],[-5.853,-14.17]],"v":[[4.752,-130.436],[4.752,-130.436],[-16.652,-58.204],[-23.907,-49.981],[-85.926,-40.054],[-86.843,-28.084],[-86.843,-28.084],[-37.479,21.794],[-33.626,31.051],[-36.372,100.039],[-24.696,108.716],[-24.696,108.716],[21.606,74.668],[32.578,73.854],[87.5,101.953],[93.804,92.239],[93.804,92.239],[81.042,26.26],[83.487,16.535],[83.487,16.535],[128.097,-40.316],[123.822,-55.243],[123.822,-55.243],[60.856,-54.412],[52.613,-59.502],[52.613,-59.502],[20.773,-127.907]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[1.612,-4.294],[0,0],[0,0],[3.168,-0.65],[9.21,-1.822],[-2.654,-3.1],[0,0],[0,0],[0,-3.1],[0,0],[-4.281,2.912],[0,0],[0,0],[-1.691,-1.2],[-2.637,-0.737],[1.113,4.3],[0,0],[0,0],[-1.984,2.227],[0,0],[0,0],[3.81,0],[0,0],[0,0],[1.284,3.1],[0,0],[0,0]],"o":[[0,0],[0,0],[-1.284,3.1],[0,0],[-3.953,0.678],[0,0],[0,0],[1.284,1.5],[0,0],[-0.92,8.55],[0,0],[0,0],[2.654,-1.5],[0.958,0.68],[3.638,1.017],[0,0],[0,0],[0,-3.1],[0,0],[0,0],[4.081,-4.883],[0,0],[0,0],[-2.654,0],[0,0],[0,0],[-4.024,-11.783]],"v":[[10.342,-108.269],[10.342,-108.269],[-12.088,-51.269],[-18.68,-45.069],[-71.273,-40.772],[-72.786,-31.169],[-72.786,-31.169],[-34.518,12.031],[-31.864,19.731],[-38.456,75.231],[-29.21,82.931],[-29.21,82.931],[11.712,58.231],[20.958,58.231],[65.239,84.191],[71.126,76.731],[71.126,76.731],[64.534,22.731],[67.188,15.031],[67.188,15.031],[108.109,-28.169],[105.456,-40.469],[105.456,-40.469],[52.634,-43.569],[46.042,-48.169],[46.042,-48.169],[23.612,-105.269]],"c":true}]},{"t":55,"s":[{"i":[[1.883,-4.294],[0,0],[0,0],[3.7,-0.65],[10.758,-1.822],[-3.1,-3.1],[0,0],[0,0],[0,-3.1],[0,0],[-5,2.912],[0,0],[0,0],[-1.975,-1.2],[-3.08,-0.737],[1.3,4.3],[0,0],[0,0],[-2.317,2.227],[0,0],[0,0],[4.45,0],[0,0],[0,0],[1.5,3.1],[0,0],[0,0]],"o":[[0,0],[0,0],[-1.5,3.1],[0,0],[-4.617,0.678],[0,0],[0,0],[1.5,1.5],[0,0],[-1.075,8.55],[0,0],[0,0],[3.1,-1.5],[1.119,0.68],[4.25,1.017],[0,0],[0,0],[0,-3.1],[0,0],[0,0],[4.767,-4.883],[0,0],[0,0],[-3.1,0],[0,0],[0,0],[-4.7,-11.783]],"v":[[-10.8,-102.3],[-10.8,-102.3],[-37,-45.3],[-44.7,-39.1],[-106.133,-34.803],[-107.9,-25.2],[-107.9,-25.2],[-63.2,18],[-60.1,25.7],[-67.8,81.2],[-57,88.9],[-57,88.9],[-9.2,64.2],[1.6,64.2],[53.323,90.16],[60.2,82.7],[60.2,82.7],[52.5,28.7],[55.6,21],[55.6,21],[103.4,-22.2],[100.3,-34.5],[100.3,-34.5],[38.6,-37.6],[30.9,-42.2],[30.9,-42.2],[4.7,-99.3]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[-39.071,-17.523],[-0.764,-17.411],[0,0],[17.667,0],[1.869,90.758],[0,0],[0,0],[-13.024,0]],"o":[[0,0],[13.024,1.003],[0,0],[0,0],[0,92.831],[-17.667,0],[0,0],[0.935,-17.757],[41.845,-19.596],[0,0]],"v":[[-5.504,-119.714],[-3.696,-119.714],[74.447,-91.891],[97.721,-65.072],[97.721,-5.28],[-4.6,127.814],[-106.921,-2.137],[-106.921,-64.002],[-88.29,-89.818],[-5.504,-119.714]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.764,"y":0},"t":13,"s":[{"i":[[0,0],[0,0],[-19.582,-22.963],[-0.383,-22.817],[0,0],[8.854,0],[0.937,118.934],[0,0],[0,0],[-6.527,0]],"o":[[0,0],[6.527,1.315],[0,0],[0,0],[0,121.651],[-8.854,0],[0,0],[0.468,-23.27],[20.972,-25.68],[0,0]],"v":[[-5.053,-158.136],[-4.147,-158.136],[35.018,-121.676],[46.682,-86.531],[46.682,-8.176],[-4.6,166.236],[-55.882,-4.057],[-55.882,-85.128],[-46.544,-118.959],[-5.053,-158.136]],"c":true}]},{"i":{"x":0.614,"y":1},"o":{"x":0.167,"y":0.167},"t":21,"s":[{"i":[[0,0],[0,0],[-36.397,-23.702],[-0.712,-23.551],[0,0],[16.457,0],[1.741,122.762],[0,0],[0,0],[-12.132,0]],"o":[[0,0],[12.132,1.357],[0,0],[0,0],[0,125.566],[-16.457,0],[0,0],[0.871,-24.019],[38.981,-26.506],[0,0]],"v":[[-5.443,-163.357],[-3.757,-163.357],[69.037,-125.723],[90.718,-89.446],[90.718,-8.57],[-4.6,171.457],[-99.918,-4.318],[-99.918,-87.999],[-82.562,-122.919],[-5.443,-163.357]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":27,"s":[{"i":[[0,0],[0,0],[-59.948,-29.521],[-1.172,-29.333],[0,0],[27.106,0],[2.868,152.898],[0,0],[0,0],[-19.983,0]],"o":[[0,0],[19.983,1.69],[0,0],[0,0],[0,156.391],[-27.106,0],[0,0],[1.434,-29.915],[64.204,-33.013],[0,0]],"v":[[-5.988,-204.453],[-3.212,-204.453],[116.684,-157.581],[152.394,-112.398],[152.394,-11.668],[-4.6,212.553],[-161.594,-6.372],[-161.594,-110.596],[-133.008,-154.088],[-5.988,-204.453]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[0,0],[0,0],[-59.556,-26.2],[-1.164,-26.033],[0,0],[26.929,0],[2.849,135.7],[0,0],[0,0],[-19.852,0]],"o":[[0,0],[19.852,1.5],[0,0],[0,0],[0,138.8],[-26.929,0],[0,0],[1.425,-26.55],[63.784,-29.3],[0,0]],"v":[[-5.979,-181],[-3.221,-181],[115.891,-139.4],[151.368,-99.3],[151.368,-9.9],[-4.6,189.1],[-160.568,-5.2],[-160.568,-97.7],[-132.168,-136.3],[-5.979,-181]],"c":true}]},{"t":55,"s":[{"i":[[0,0],[0,0],[-64.8,-26.2],[-1.267,-26.033],[0,0],[29.3,0],[3.1,135.7],[0,0],[0,0],[-21.6,0]],"o":[[0,0],[21.6,1.5],[0,0],[0,0],[0,138.8],[-29.3,0],[0,0],[1.55,-26.55],[69.4,-29.3],[0,0]],"v":[[-6.1,-181],[-3.1,-181],[126.5,-139.4],[165.1,-99.3],[165.1,-9.9],[-4.6,189.1],[-174.3,-5.2],[-174.3,-97.7],[-143.4,-136.3],[-6.1,-181]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1.854,0.749],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"User-promoted","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/ic_pin.json b/TMessagesProj/src/main/res/raw/ic_pin.json new file mode 100644 index 000000000..fcf564862 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/ic_pin.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":60,"ip":0,"op":120,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":32,"s":[290,268,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":35,"s":[290,306,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":40,"s":[290,258,0],"to":[0,0,0],"ti":[0,0,0]},{"t":45,"s":[290,268,0]}],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":30,"s":[0]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":35,"s":[-6]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":40,"s":[3]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":46,"s":[-2]},{"t":51,"s":[0]}],"ix":10},"p":{"a":0,"k":[-22,225.242,0],"ix":2},"a":{"a":0,"k":[50,100,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Pin","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[-70]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.6],"y":[0]},"t":21,"s":[20]},{"t":33,"s":[-25]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[-84.078,136.681,0],"to":[62.078,-209.923,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":0.97},"o":{"x":0.8,"y":0},"t":23,"s":[229.922,-217.319,0],"to":[-73.499,6.818,0],"ti":[0,0,0]},{"i":{"x":0.454,"y":1},"o":{"x":0.3,"y":0.477},"t":35,"s":[121.14,-79.244,0],"to":[0,0,0],"ti":[0,0,0]},{"t":52,"s":[117.922,-63.319,0]}],"ix":2},"a":{"a":0,"k":[-0.078,-0.077,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"t":11,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.3,"y":0},"t":0,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[20.022,-13.297],[3.194,3.194],[-5.784,10.02],[-47.616,53.695],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-42.204,37.036],[-14.847,9.861],[-2.434,-2.434],[12.035,-20.85],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-136.654,154.899],[-163.6,164.9],[-158.576,146.218],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.8,"y":0},"t":23,"s":[{"i":[[22.651,7.683],[0,0],[0,0],[8.244,-1.288],[2.539,2.539],[-0.403,4.264],[-9.355,10.145],[11.638,48.666],[-8.869,7.791],[-16.198,1.588],[-18.505,-9.809],[0,0],[-21.239,-19.396],[0,0],[15.503,-15.503],[8.018,-6.936],[1.858,-23.456],[12.128,-2.613]],"o":[[-43.538,-14.768],[0,0],[-5.882,7.456],[-6.114,0.956],[-1.935,-1.935],[0.838,-8.872],[0,0],[-5.116,-21.393],[6.784,-5.96],[15.427,-1.512],[4.338,-3.765],[15.503,-15.503],[0,0],[18.864,18.607],[0,0],[8.813,11.486],[-1.601,20.216],[-4.575,0.762]],"v":[[2.874,119.855],[-61.837,85.113],[-64.246,85.636],[-87.981,98.807],[-101.997,96.454],[-104.236,86.825],[-88.404,55.325],[-126.708,-15.522],[-113.061,-64.163],[-75.927,-78.896],[-21.024,-66.322],[-9.116,-76.07],[61.482,-76.815],[74.583,-63.075],[76.88,6.603],[68.085,16.549],[82.382,76.958],[46.874,120.336]],"c":true}]},{"i":{"x":0.7,"y":1},"o":{"x":0.167,"y":0.167},"t":33,"s":[{"i":[[7.201,4.974],[0,0],[0,0],[18.27,-11.51],[1.583,2.769],[-4.983,9.164],[-41.923,47.215],[1.732,7.241],[-10.257,10.097],[-7.517,0.236],[-2.753,-1.459],[0,0],[-19.759,-19.485],[0,0],[18.905,-18.905],[1.193,-1.032],[0.276,-3.49],[13.58,-1.524]],"o":[[-6.478,-2.197],[0,0],[-36.799,32.634],[-13.548,8.536],[-1.657,-2.898],[10.369,-19.068],[0,0],[-9.699,-12.121],[4.84,-4.717],[2.296,-0.225],[0.645,-0.56],[18.905,-18.905],[0,0],[19.405,19.367],[0,0],[1.311,1.709],[-0.238,14.499],[-5.579,0.93]],"v":[[38.647,144.153],[-37.376,72.589],[-46.672,80.328],[-129.955,145.978],[-154.434,154.716],[-149.609,137.853],[-71.972,37.514],[-142.789,-39.422],[-140.758,-77.303],[-121.188,-85.879],[-17.258,-86.562],[35.586,-140.361],[106.1,-140.472],[138.693,-107.785],[139.035,-37.407],[86.654,16.422],[86.228,121.171],[59.466,148.849]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.3,"y":0},"t":35,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[20.022,-13.297],[3.194,3.193],[5.66,3.934],[-47.616,53.695],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-42.204,37.036],[-4.178,-2.678],[-2.434,-2.434],[12.035,-20.85],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[47.23,154.364],[-33.1,70.4],[-43.6,79.4],[-136.654,154.899],[-149.486,149.954],[-157.451,144.269],[-69.1,34.4],[-147.796,-51.796],[-147.796,-87.796],[-131.296,-95.296],[-25.332,-78.976],[25.668,-124.887],[96.168,-124.887],[129.57,-90.387],[129.57,-19.887],[78.57,26.024],[89.23,134.864],[63.997,159.797]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":40,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[19.56,-13.406],[4.136,3.243],[3.389,4.721],[-44.499,50.18],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-39.159,34.364],[-5.104,-1.789],[-3.007,-2.41],[12.781,-20.901],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-131.435,151.054],[-145.43,146.031],[-154.111,139.447],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]},{"t":52,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[17.61,-13.865],[8.109,3.45],[-6.186,8.042],[-31.36,35.363],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-26.322,23.099],[-9.008,1.959],[-5.419,-2.305],[15.926,-21.117],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-109.429,134.845],[-128.33,129.488],[-140.029,119.12],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pin-and-unpin","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Line","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":23,"s":[-25.408,280.081,0],"to":[0,0,0],"ti":[0,0,0]},{"t":35,"s":[-25.408,240.081,0]}],"ix":2},"a":{"a":0,"k":[-41.408,189.581,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-130.899,189.147],[77.583,189.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-42.372,184.791],"ix":2},"a":{"a":0,"k":[-42.372,184.791],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.7],"y":[0.943]},"o":{"x":[0.8],"y":[0]},"t":24,"s":[50]},{"t":35,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.7],"y":[0.943]},"o":{"x":[0.8],"y":[0]},"t":24,"s":[50]},{"t":35,"s":[0]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":24,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/ic_unpin.json b/TMessagesProj/src/main/res/raw/ic_unpin.json new file mode 100644 index 000000000..b83a4b89d --- /dev/null +++ b/TMessagesProj/src/main/res/raw/ic_unpin.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":60,"ip":0,"op":120,"w":512,"h":512,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 3","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.423,"y":1},"o":{"x":0.312,"y":0},"t":0,"s":[236.014,476.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.71,"y":1},"o":{"x":0.7,"y":0},"t":29,"s":[236.014,456.705,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.29,"y":0},"t":37,"s":[236.014,491.705,0],"to":[0,0,0],"ti":[0,0,0]},{"t":48,"s":[236.014,441.705,0]}],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":8,"s":[102,98,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":17,"s":[98,102,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":26,"s":[102,98,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":37,"s":[95,95,100]},{"i":{"x":[0.71,0.71,0.71],"y":[1,1,1]},"o":{"x":[0.29,0.29,0.29],"y":[0,0,0]},"t":44,"s":[95,95,100]},{"t":54,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":0,"s":[-6]},{"i":{"x":[0.499],"y":[1]},"o":{"x":[0.607],"y":[0]},"t":8,"s":[12]},{"i":{"x":[0.372],"y":[1]},"o":{"x":[0.435],"y":[0]},"t":17,"s":[-28]},{"i":{"x":[0.672],"y":[1]},"o":{"x":[0.658],"y":[0]},"t":26,"s":[0]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":37,"s":[-24]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":43,"s":[-24]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":50,"s":[-18]},{"t":56,"s":[-24]}],"ix":10},"p":{"a":0,"k":[31.986,32.537,0],"ix":2},"a":{"a":0,"k":[50,100,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Pin","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.346],"y":[0.786]},"o":{"x":[0.475],"y":[0]},"t":37,"s":[-25]},{"i":{"x":[0.599],"y":[1]},"o":{"x":[0.271],"y":[4.632]},"t":49,"s":[100]},{"t":54,"s":[100]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.797,"y":1},"o":{"x":0.261,"y":0},"t":0,"s":[113.922,-7.319,0],"to":[0,0,0],"ti":[-11.386,5.411,0]},{"i":{"x":0.684,"y":0.826},"o":{"x":0.621,"y":0},"t":37,"s":[128.497,-87.071,0],"to":[28.22,-63.562,0],"ti":[-19.046,-29.394,0]},{"i":{"x":0.506,"y":1},"o":{"x":0.203,"y":0.126},"t":44,"s":[241.015,-156.809,0],"to":[24.476,41.2,0],"ti":[52.022,-36.485,0]},{"i":{"x":0.658,"y":1},"o":{"x":0.167,"y":0},"t":54,"s":[186.712,13.283,0],"to":[0,0,0],"ti":[0,0,0]},{"t":60,"s":[205.024,-19.461,0]}],"ix":2},"a":{"a":0,"k":[-0.078,-0.077,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.71,"y":1},"o":{"x":0.167,"y":0},"t":0,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[10.773,-10.884],[8.109,3.45],[-6.186,8.042],[-31.36,35.363],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-26.322,23.099],[-9.008,1.959],[-5.419,-2.305],[15.926,-21.117],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-77.509,107.801],[-100.538,95.232],[-113.026,84.443],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":8,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[5.616,-2.364],[6.24,3.352],[7.542,0.896],[-37.54,42.332],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-32.359,28.397],[-9.881,-4.145],[-4.284,-2.354],[14.447,-21.016],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-77.318,105.283],[-99.386,97.823],[-119.175,93.831],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]},{"i":{"x":0.71,"y":1},"o":{"x":0.29,"y":0},"t":17,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[18.096,-12.795],[4.217,3.247],[4.112,2.94],[-32.808,36.823],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-23.542,22.483],[-4.517,-2.286],[-3.056,-2.408],[12.845,-20.906],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[29.686,162.42],[-48.314,84.42],[-58.814,93.42],[-114.674,137.321],[-124.717,127.658],[-134.131,114.062],[-84.314,48.42],[-160.814,-29.58],[-160.814,-65.58],[-144.314,-73.08],[-31.814,-76.08],[28.186,-137.58],[98.686,-137.58],[134.686,-101.58],[134.686,-31.08],[74.686,30.42],[71.686,142.92],[46.452,167.854]],"c":true}]},{"i":{"x":0.672,"y":1},"o":{"x":0.681,"y":0},"t":26,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[19.633,-13.196],[3.4,3.204],[8.232,1.439],[-46.932,52.923],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-41.535,36.449],[-5.457,-5.479],[-2.56,-2.429],[12.198,-20.862],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-129.479,149.035],[-141.08,141.314],[-151.023,137.074],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]},{"i":{"x":0.44,"y":0.732},"o":{"x":0.167,"y":0},"t":37,"s":[{"i":[[12.742,4.584],[25.704,33.529],[0,0],[20.022,-13.297],[3.194,3.193],[-5.784,10.02],[-6.788,5.981],[4.727,15.642],[-10.5,10.5],[-15.2,1.449],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[2.285,-25.872],[13.833,-1.333]],"o":[[-12.742,-4.584],[-1.367,-0.821],[-42.204,37.036],[-14.847,9.861],[-2.434,-2.434],[12.035,-20.85],[-32.321,-29.008],[-2.571,-8.509],[4.5,-4.5],[24.837,-2.368],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[-1.678,18.999],[-5.755,0.959]],"v":[[28.513,148],[-52.461,93.855],[-55.258,94.067],[-136.654,154.899],[-158.194,158.544],[-158.576,146.217],[-97.266,47.726],[-149.832,-36.435],[-145.6,-79.6],[-119.325,-93.505],[-36.913,-73.837],[13.868,-124.603],[84.368,-124.603],[120.368,-88.603],[120.368,-18.103],[70.278,33.458],[92.928,117.383],[59.543,152.192]],"c":true}]},{"i":{"x":0.216,"y":1},"o":{"x":0.29,"y":0.139},"t":44,"s":[{"i":[[22.651,7.683],[0,0],[0,0],[8.244,-1.288],[2.539,2.539],[-0.403,4.264],[-9.355,10.145],[11.638,48.666],[-8.869,7.791],[-16.198,1.588],[-18.505,-9.809],[0,0],[-21.239,-19.396],[0,0],[15.503,-15.503],[8.018,-6.936],[1.858,-23.456],[12.128,-2.613]],"o":[[-43.538,-14.768],[0,0],[-5.882,7.456],[-6.114,0.956],[-1.935,-1.935],[0.838,-8.872],[0,0],[-5.116,-21.393],[6.784,-5.96],[15.427,-1.512],[4.338,-3.765],[15.503,-15.503],[0,0],[18.864,18.607],[0,0],[8.813,11.486],[-1.601,20.216],[-4.575,0.762]],"v":[[2.874,119.855],[-61.837,85.113],[-64.246,85.636],[-87.981,98.807],[-101.997,96.454],[-104.236,86.825],[-88.404,55.325],[-126.708,-15.522],[-113.061,-64.163],[-75.927,-78.896],[-21.024,-66.322],[-9.116,-76.07],[61.482,-76.815],[74.583,-63.075],[76.88,6.603],[68.085,16.549],[82.382,76.958],[46.874,120.336]],"c":true}]},{"t":54,"s":[{"i":[[4.5,4.5],[0,0],[0,0],[20.022,-13.297],[3.194,3.194],[-5.784,10.02],[-47.616,53.695],[0,0],[-10.5,10.5],[-6,0],[0,0],[0,0],[-19.5,-19.5],[0,0],[19.5,-19.5],[0,0],[0,0],[13.833,-1.333]],"o":[[0,0],[0,0],[-42.204,37.036],[-14.847,9.861],[-2.434,-2.434],[12.035,-20.85],[0,0],[-10.5,-10.5],[4.5,-4.5],[0,0],[0,0],[19.5,-19.5],[0,0],[19.5,19.5],[0,0],[0,0],[0,13.5],[-5.755,0.959]],"v":[[44.9,148.4],[-33.1,70.4],[-43.6,79.4],[-136.654,154.899],[-163.6,164.9],[-158.576,146.218],[-69.1,34.4],[-145.6,-43.6],[-145.6,-79.6],[-129.1,-87.1],[-16.6,-90.1],[43.4,-151.6],[113.9,-151.6],[149.9,-115.6],[149.9,-45.1],[89.9,16.4],[86.9,128.9],[61.667,153.833]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Pin-and-unpin","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Line","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[28.578,47.376,0],"ix":2},"a":{"a":0,"k":[-41.408,189.581,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-130.899,189.147],[77.583,189.295]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-42.372,184.791],"ix":2},"a":{"a":0,"k":[-42.372,184.791],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.663],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.682],"y":[0]},"t":28,"s":[85]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":37,"s":[75]},{"t":42,"s":[50]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.663],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.682],"y":[0]},"t":28,"s":[15]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.29],"y":[0]},"t":37,"s":[25]},{"t":42,"s":[50]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":42,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/permission_map.svg b/TMessagesProj/src/main/res/raw/permission_map.svg new file mode 100644 index 000000000..a6746e3bf --- /dev/null +++ b/TMessagesProj/src/main/res/raw/permission_map.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/permission_map_dark.svg b/TMessagesProj/src/main/res/raw/permission_map_dark.svg new file mode 100644 index 000000000..75260ca3c --- /dev/null +++ b/TMessagesProj/src/main/res/raw/permission_map_dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/permission_pin.svg b/TMessagesProj/src/main/res/raw/permission_pin.svg new file mode 100644 index 000000000..615e89f44 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/permission_pin.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/permission_pin_dark.svg b/TMessagesProj/src/main/res/raw/permission_pin_dark.svg new file mode 100644 index 000000000..e0e0f97f8 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/permission_pin_dark.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/raw/player_prev.json b/TMessagesProj/src/main/res/raw/player_prev.json new file mode 100644 index 000000000..50890ec88 --- /dev/null +++ b/TMessagesProj/src/main/res/raw/player_prev.json @@ -0,0 +1 @@ +{"v":"5.7.1","fr":60,"ip":0,"op":25,"w":28,"h":28,"nm":"Previous track lottie","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Triangle 4","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":4,"s":[0]},{"t":9,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.73,"y":1},"o":{"x":0.567,"y":0},"t":4,"s":[25.88273333333333,14.04106666666667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.57,"y":1},"o":{"x":0.206,"y":0},"t":15,"s":[16.0244,14.04106666666667,0],"to":[0,0,0],"ti":[0,0,0]},{"t":27,"s":[17.4244,14.04106666666667,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.73,0.73,0.667],"y":[1,1,1]},"o":{"x":[0.56,0.56,0.333],"y":[0,0,0]},"t":4,"s":[12.133333333333333,12.133333333333333,100]},{"i":{"x":[0.614,0.614,0.833],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.167],"y":[0,0,0]},"t":15,"s":[49.46666666666667,49.46666666666667,100]},{"t":25,"s":[46.666666666666664,46.666666666666664,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.47,-0.33],[0,0],[-1.59,2.26],[0,1.03],[0,0],[2.77,0],[0.85,-0.59],[0,0],[-1.59,-2.26]],"o":[[0,0],[2.26,1.59],[0.59,-0.84],[0,0],[0,-2.76],[-1.03,0],[0,0],[-2.26,1.59],[0.33,0.47]],"v":[[-15.542,4.083],[9.778,21.943],[16.748,20.733],[17.658,17.853],[17.658,-17.857],[12.658,-22.857],[9.778,-21.947],[-15.542,-4.087],[-16.752,2.883]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":27,"st":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Triangle 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.8,"y":1},"o":{"x":0.567,"y":0},"t":0,"s":[17.4244,14.04106666666667,0],"to":[0,0,0],"ti":[0,0,0]},{"t":15,"s":[2.5494,14.04106666666667,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.766,0.766,0.667],"y":[1,1,1]},"o":{"x":[0.56,0.56,0.333],"y":[0,0,0]},"t":0,"s":[46.666666666666664,46.666666666666664,100]},{"t":15,"s":[18.666666666666668,18.666666666666668,100]}],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":1,"k":[{"i":{"x":0.73,"y":1},"o":{"x":0.56,"y":0},"t":4,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[17.659,-24.824],[-25.588,-24.826],[-25.588,25.095],[17.659,25.097]],"c":true}]},{"t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[18.753,-24.784],[-1.119,-24.66],[-1.119,25.261],[18.753,25.137]],"c":true}]}],"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.47,-0.33],[0,0],[-1.59,2.26],[0,1.03],[0,0],[2.77,0],[0.85,-0.59],[0,0],[-1.59,-2.26]],"o":[[0,0],[2.26,1.59],[0.59,-0.84],[0,0],[0,-2.76],[-1.03,0],[0,0],[-2.26,1.59],[0.33,0.47]],"v":[[-15.542,4.083],[9.778,21.943],[16.748,20.733],[17.658,17.853],[17.658,-17.857],[12.658,-22.857],[9.778,-21.947],[-15.542,-4.087],[-16.752,2.883]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Triangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":27,"st":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Rectangle 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[4.199999999999999,13.999999999999998,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[46.666666666666664,46.666666666666664,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.21,0],[0,-2.21],[0,-6.75],[0,-2.23],[2.21,0],[0,2.23],[0,6.97],[0,2.21]],"o":[[2.21,0],[0,2.21],[0,7.25],[0,2.23],[-2.21,0],[0,-2.23],[0,-7.03],[0,-2.21]],"v":[[0,-25],[4,-21],[4,0.09],[4,21],[0,25],[-4,21],[-4,0.09],[-4,-21]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":27,"st":1,"bm":0}],"markers":[]} \ 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 2accc9ad7..b45248e72 100644 --- a/TMessagesProj/src/main/res/values-ar/strings.xml +++ b/TMessagesProj/src/main/res/values-ar/strings.xml @@ -210,7 +210,7 @@ مائل رمز يتوسطه خط - خط سفلي + تسطير عادي يحتاج **تيليجرام** إلى الوصول لجهات اتصالك لكي تتمكن من التواصل مع أصدقائك عبر جميع أجهزتك، ستتم مزامنة جهات اتصالك باستمرار مع خوادم تيليجرام السحابية شديدة التشفير. ليس الآن @@ -228,26 +228,29 @@ اذهب إلى الإعدادات عرض الملف الشخصي فتح القناة + فتح المجموعة إرسال رسالة إشارة - Notifications muted - Notifications muted for %1$s - Notifications unmuted - %1$d messages deleted - Message deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted + تم كتم الإشعارات + الإشعارات مكتومة لـ %1$s + تم إلغاء كتم الإشعارات + تم حذف %1$d رسالة + تم حذف %1$d رسالة + تم حذف رسالتين + تم حذف %1$d رسائل + تم حذف %1$d رسالة + تم حذف %1$d رسالة ما من نتائج ما من نتائج - Try a new search. - صوتيات - ملفات - روابط - رسائل صوتية - وسائط + جرّب بحثًا جديدًا. + سيتم عرض الصوتيات من جميع محادثاتك هنا. + سيتم عرض الملفات من جميع محادثاتك هنا. + سيتم عرض الروابط من جميع محادثاتك هنا. + سيتم عرض الرسائل الصوتية من جميع محادثاتك هنا. + سيتم عرض الوسائط من جميع محادثاتك هنا. محادثات + تم تثبيت الرسالة + أُلغي تثبيت الرسالة ترقية إلى مشرف تعديل صلاحيات المشرف @@ -441,7 +444,7 @@ حذف رسائل الآخرين حذف الرسائل إضافة مشرفين جدد - البقاء مجهولًا + البقاء متخفيًا إزالة الإشراف نقل ملكية المجموعة نقل ملكية القناة @@ -473,7 +476,7 @@ إرسال الوسائط إرسال الاستفتاءات إرسال الملصقات والصور المتحركة - تضمين الروابط + معاينة للروابط تغيير معلومات المحادثة تثبيت الرسائل إضافة مستخدمين @@ -482,7 +485,7 @@ لا وسائط لا استفتاءات لا ملصقات وصور متحركة - لا روابط مضمَّنة + بلا معاينة للروابط لا يمكنه تغيير المعلومات لا تثبيت رسائل لا يمكنه إضافة مستخدمين @@ -563,6 +566,7 @@ تم تفعيل الوضع البطيء. لا يمكنك إرسال أكثر من رسالة مرةً واحدة. تم تفعيل الوضع البطيء. لا يمكنك تحديد المزيد من العناصر. المعذرة، هذا النص طويل للغاية ولا يمكن إرساله برسالة واحدة.\n\nتم تفعيل الوضع البطيء. لا يمكنك إرسال عدة رسائل مرةً واحدة. + **%1$s** promoted to admin استفتاء جديد اختبار جديد @@ -703,7 +707,7 @@ تثبيت الرسائل إرسال الاستفتاءات إرسال الرسائل - تضمين الروابط + معاينة الروابط قراءة الرسائل غيّرَ صلاحيات %1$s تغيير معلومات القناة @@ -882,7 +886,7 @@ إضافة %1$s لجهات الاتصال عرض جهة الاتصال هل ترغب بحظر **%1$s** من مراسلتك والاتصال بك على تيليجرام؟ - Do you want to block messages from **%1$s**? + هل ترغب بحظر الرسائل من **%1$s**؟ هل ترغب حقًا في التبليغ عن إزعاج من هذا المستخدم؟ هل ترغب حقًا في التبليغ عن إزعاج من هذه المجموعة؟ هل ترغب حقًا في التبليغ عن إزعاج من هذه القناة؟ @@ -895,10 +899,12 @@ اضغط هنا للوصول للصور المتحركة المحفوظة تثبيت إشعار جميع الأعضاء + Also pin for %1$s إلغاء التثبيت تثبيت الرسالة إلغاء تثبيت الرسالة - هل ترغب في تثبيت هذه الرسالة في هذه المجموعة؟ + Do you want to pin an older message while leaving a more recent one pinned? + هل تريد تثبيت هذه الرسالة لكل الأعضاء في المجموعة؟ هل ترغب في تثبيت هذه الرسالة في هذه القناة؟ هل ترغب في تثبيت هذه الرسالة أعلى هذه المحادثة؟ هل ترغب في إلغاء تثبيت هذه الرسالة؟ @@ -923,6 +929,7 @@ أخرى الوصف رسالة مثبتة + الرسالة السابقة استفتاء مثبت معدلة تعديل الرسالة @@ -970,11 +977,11 @@ قام مشرفو هذه المجموعة بتقييدك من إرسال الملصقات. قام مشرفو هذه المجموعة بتقييدك من إرسال الصور المتحركة إليها. قام مشرفو هذه المجموعة بتقييدك من الكتابة هنا. - لا يُسمحُ بإرسال الوسائط في هذه المجموعة. - لا يُسمحُ بإرسال محتوى استعلامي في هذه المجموعة. - لا يُسمحُ بإرسال الملصقات في هذه المجموعة. - لا يُسمحُ بإرسال الصور المتحركة في هذه المجموعة. - لا يُسمحُ بكتابة الرسائل في هذه المجموعة. + لا يُسمح بإرسال الوسائط في هذه المجموعة. + لا يُسمح بإرسال محتوى استعلامي في هذه المجموعة. + لا يُسمح بإرسال الملصقات في هذه المجموعة. + لا يُسمح بإرسال الصور المتحركة في هذه المجموعة. + لا يُسمح بكتابة الرسائل في هذه المجموعة. مشرف "تثبيت ملفات APK محظور لهذا التطبيق، يمكنك السماح بهذا من إعدادات النظام. " الرسائل غير المقروءة @@ -996,7 +1003,7 @@ انقر لأخذ صورة، اضغط باستمرار لتصوير مقطع مرئي انقر للعرض في قائمة. إرسال بدون صوت - إرسال الآن> + إرسال الآن إعادة جدولة اليوم جدولة @@ -1041,25 +1048,28 @@ د س أس - to private messages and groups - + إلى الرسائل الخاصة والمجموعات نقل ملكية البوت - This will transfer the **full owner** rights for the bot to the selected user. + سيتم نقل **جميع حقوق الملكية** للبوت إلى المستخدم المحدّد. تغيير المالك - You can transfer bot only if you have: + تستطيع نقل البوت فقط إذا: كتابة تعليق - Comments - Comment + التعليقات + تعليق الردود ما من تعليقات هنا بعد... - No replies here yet... + ما من ردود هنا بعد... عرض في المحادثة - إرسال كمجهول + الإرسال متخفيًا بداية المناقشة عرض الموضوع - Choose date + اختيار تاريخ تساعدك هذه المحادثة في تتبع الردود على تعليقاتك في القنوات. - Sorry, this post has been removed from the discussion group. + المعذرة، تمت إزالة هذا المنشور من مجموعة المناقشة. + إلغاء تثبيت كل الرسائل + إخفاء الرسائل المثبّتة + Pinned messages hidden + Pinned messages will be shown again if a new message is pinned. عيّن %1$s عداد التدمير الذاتي ليصبح %2$s قمت بتعيين عداد التدمير الذاتي ليصبح %1$s @@ -1161,7 +1171,7 @@ ثبّتَت %1$s استفتاء %2$s ثبت %1$s الاختبار «%2$s» %1$s ثبت صورة - %1$s ثبت لعبة + ثبّت %1$s لعبة ثبّتَت %1$s نتيجة لعبة ثبت %1$s مقطعًا مرئيًا ثبت %1$s ملفًا @@ -1175,6 +1185,25 @@ ثبت %1$s موقعًا حيًا ثبت %1$s صورةً متحركة ثبت %1$s ملفًا صوتيًا + ثبّت %1$s \"%2$s\" + ثبّت %1$s رسالة + ثبّت %1$s استفتاء %2$s + ثبّت %1$s اختبار %2$s + ثبّت %1$s صورة + ثبّت %1$s لعبة + ثبّت %1$s نتيجة لعبة + ثبّت %1$s مقطعًا مرئيًا + ثبّت %1$s ملفًا + ثبّت %1$s فاتورة + ثبّت %1$s ملصقًا + %1$s pinned a %2$s sticker + ثبّت %1$s رسالة صوتيّة + ثبّت %1$s رسالة مرئية + %1$s pinned a contact %2$s + ثبّت %1$s خريطة + ثبّت %1$s موقعًا مباشرًا + ثبّت %1$s صورة متحركة + ثبّت %1$s ملفًا صوتيًا تيليجرام اختر جهة اتصال @@ -1211,10 +1240,13 @@ مرتبة حسب تاريخ آخر ظهور إضافة %1$s رقم الهاتف - You have no contacts on Telegram yet + ليس لديك جهات اتصال على تيليجرام بعد دعوة الأصدقاء لتجربة تيليجرام - Find people nearby to chat with - Search people by username + اعثر على الأشخاص القريبين للتحدث معهم + البحث عن أشخاص عبر اسم المستخدم + جهة اتصال جديدة + رقم الهاتف **%1$s** ليس في قائمة جهات اتصالك. هل تريد إضافته؟ + إضافة جهة اتصال إضافة أشخاص... ستتمكن من إضافة المزيد من الأعضاء بعد انتهاءك من إنشاء المجموعة. @@ -1422,7 +1454,7 @@ مجدول تلقائي الجدولة - إعدادات النظام الافتراضية + إعدادات النظام استخدام التوقيت المحلي للشروق والغروب تحديث الموقع يتطلب حساب مواعيد الشروق والغروب التحقق لمرة واحدة من موقعك التقريبي. يرجى العلم أن موقعك يتم حفظه في جهازك فقط.\n\nالغروب: %1$s\nالشروق: %2$s @@ -1510,7 +1542,7 @@ أيمن صباح الخير!👋 صباح الخير - طلعت يا محلا نورها يا شمس الشموسة + ماهو الوقت الآن؟ الوقت صباح هنا في *دبي* 😎 استخدام نمط آخر يمكنك أيضًا اختيار أحد الأنماط الحالية كأساس لنمطك الجديد. @@ -1622,7 +1654,7 @@ ماهو الوقت الآن؟ الوقت صباح هنا في دبي 😎 اضغط على «تعيين» لتطبيق الخلفية. - طلعت يا محلا نورها يا شمس الشموسة + استمتع بالخلفية. تعيين كخلفية بحث بواسطة اللون البحث عن خلفيات @@ -2310,6 +2342,12 @@ على بُعد %1$s ك.م على بُعد %1$s قدم على بُعد %1$s ميل + %1$s قدم + %1$s ميل + ميل + كم + %1$s م + %1$s كم يبعد %1$s م عنك يبعد %1$s كم عنك يبعد %1$s ق عنك @@ -2342,7 +2380,9 @@ تم تحديث الموقع %1$s تم تحديثه الآن أنت و%1$s - %1$s يتم مشاركته مع %2$s + %1$s تتم مشاركته مع %2$s + %1$s sharing with %2$s + %1$s sharing with %2$s إيقاف الكل تقوم بمشاركة موقعك الحي مع %1$s اختر المدة التي سيتمكن خلالها %1$s من مشاهدة موقعك الفعلي. @@ -2371,6 +2411,19 @@ تعيين هذا الموقع سيكون بإمكان الناس العثور على مجموعتك في قسم «الأشخاص القريبون». الأماكن في هذه المنطقة + تنبيه الاقتراب + نبّهني عندما يكون %1$s على بعد %2$s + Notify when someone is within %1$s + أنت أقرب من %1$s + مشاركة الموقع + مشاركة + لكي يعمل التنبيه؛ شارك موقعك المباشر في هذه المحادثة. + التنبيه عندما يكون %1$s قريبًا + التنبيه عندما يكون أعضاء المجموعة قريبين + Proximity alert set + We will notify you once %1$s is within %2$s from you. + We will notify you once someone is within %1$s from you. + Proximity alert cancelled عرض في لائحة عرض كمصفوفة @@ -2476,8 +2529,43 @@ المقطع المرئي الأساسي للقناة. صورة العرض الأساسية للمجموعة. المقطع المرئي الأساسي للمجموعة. - Photo saved to gallery - Video saved to gallery + تم حفظ الصورة في المعرض + تم حفظ المقطع المرئي في المعرض + تم حفظ الصورة في التنزيلات + تم حفظ المقطع في التنزيلات + تم حفظ الصورة المتحركة في التنزيلات + File saved to music + File saved to downloads + %1$d files saved to downloads + File saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d photos saved to gallery + Photo saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d videos saved to gallery + Video saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d files saved to music + File saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d items saved to gallery + One item saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery التحقق بخطوتين التحقق بخطوتين @@ -2761,7 +2849,10 @@ عاد un1 للمجموعة انضم un1 للمجموعة لقد عُدتَ للمجموعة - لقد سمحت لهذا البوت بمراسلتك عندما تسجل دخولك إلى %1$s + un1 الآن على بعد %1$s منك + أنت الآن على بعد %1$s من un1 + un1 الآن على بعد %1$s منك un2 + لقد سمحت لهذا البوت بمراسلتك عندما سجّلت دخولك إلى %1$s استلم %1$s الوثائق التالية: %2$s التفاصيل الشخصية العنوان @@ -2917,9 +3008,9 @@ المعذرة، مشرفو هذه المجموعة قيدوك من إرسال الملصقات. المعذرة، قام مشرفو هذه المجموعة بتقييدك من إرسال الوسائط. المعذرة، قام مشرفو هذه المجموعة بتقييدك من إرسال الاستفتاءات. - المعذرة، لا يُسمحُ بإرسال الملصقات في هذه المجموعة. - المعذرة، لا يُسمحُ بإرسال الوسائط في هذه المجموعة. - المعذرة، لا يُسمحُ بإرسال الاستفتاءات في هذه المجموعة. + المعذرة، لا يُسمح بإرسال الملصقات في هذه المجموعة. + المعذرة، لا يُسمح بإرسال الوسائط في هذه المجموعة. + المعذرة، لا يُسمح بإرسال الاستفتاءات في هذه المجموعة. نحن متأسفون للغاية، ولكن هذا يعني أنه لا يمكنك الاشتراك بتيليجرام.\n\nعلى عكس الآخرين، نحن لا نستخدم بياناتك لاستهدافك بالإعلانات أو لأغراض تجارية أخرى. لا يخزن تيليجرام سوى المعلومات التي يحتاجها ليعمل كخدمة سحابية غنية بالميزات. يمكنك ضبط كيفية استخدامنا لبياناتك (مثل إعدادات حذف الجهات المزامَنة) في إعدادات الخصوصية والأمان.\n\nلكن إن كنت غير موافق على احتياجات تيليجرام المتواضعة بشكل عام، فلن يكون من الممكن لنا تقديم هذه الخدمة. التحقق من العمر سياسة الخصوصية وشروط الخدمة @@ -2937,6 +3028,7 @@ يحتاج تيليجرام إلى صلاحية الظهور فوق التطبيقات لتشغيل المقاطع المرئية في وضع (صورة في الصورة). الإعدادات يرجى السماح لتيليجرام بالظهور على شاشة القفل للتمكن من إجراء المكالمات دون مشاكل. + To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. النّمو المتابِعون @@ -2966,7 +3058,7 @@ %s بيانات أخرى "أعضاء المجموعة " الأعضاء الجدد حسب المصدر - اللغة الأساسية للأعضاء + لغات الأعضاء الرسائل الأحداث الأعضاء @@ -3005,11 +3097,20 @@ %1$d إضافة المشرفون النشطون الأعضاء النشطون - أشهر المضيفين + أنشط المضيفين %s للرسالة الأيام النشطة يقرؤون الرسائل عرض الملف الشخصي + اليوم + يوم أمس + المشاهدات + Public Shares + Private Shares + عرض الإحصائيات + عرض إحصائيات القناة + إحصائيات المنشور + فتح الرسالة تيليجرام سريع @@ -3138,9 +3239,9 @@ رفض معاودة الاتصال الكاميرا - Are you sure you want to call **%1$s**? + هل أنت متأكد من الاتصال بـ**%1$s**؟ مكالمة صوتية - Are you sure you want to video call **%1$s**? + هل أنت متأكد من إجراء مكالمة مرئية مع **%1$s**؟ مكالمة مرئية تتم معاودة الاتصال @@ -3244,15 +3345,21 @@ %1$d رسائل جديدة %1$d رسالة جديدة %1$d رسالة جديدة + %1$d messages unpinned + message unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned %1$d رسالة - الرسالة - الرسالتين + رسالة واحدة + رسالتين %1$d رسائل %1$d رسالة %1$d رسالة - %1$d عنصر + %1$d عنصار عنصر واحد - عنصرَين + عنصران %1$d عناصر %1$d عنصرًا %1$d عنصر @@ -3400,12 +3507,18 @@ %1$s مشاركات %1$s مشاركة %1$s مشاركة - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared + %1$s public shares + %1$s public share + %1$s public shares + %1$s public shares + %1$s public shares + %1$s public shares + %1$s مشاركة + مشاركة واحدة + مشاركتان + %1$s مشاركات + %1$s مشاركة + %1$s مشاركة %1$s حزمة ملصقات حزمة ملصقات واحدة حزمتا ملصقات @@ -3593,24 +3706,42 @@ تم تحديد %1$d من %2$d تم تحديد %1$d من %2$d تم تحديد %1$d من %2$d - View %1$d Replies - View %1$d Reply - View %1$d Replies - View %1$d Replies - View %1$d Replies - View %1$d Replies - %1$d Replies - %1$d Reply - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Comments - %1$d Comment - %1$d Comments - %1$d Comments - %1$d Comments - %1$d Comments + عرض %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 Pinned Messages + Pinned Message + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages مجموعة قناة @@ -3684,6 +3815,7 @@ العنوان الرأسية موقعي + التنبيه عندما يكون في النطاق دقة المقطع المرئي الأبعاد أخذ صورة أخرى @@ -3737,6 +3869,7 @@ تم التبديل إلى الكاميرا الخلفية الكاميرا مفتوحة الكاميرا مغلقة + قائمة الرسائل المثبّتة yyyy MMMM MMM dd yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'ذكّرني اليوم عند\' HH:mm \'ذكّرني بتاريخ\' d MMM \'عند\' HH:mm \'ذكّرني بتاريخ\' d MMM yyyy \'عند\' HH:mm - Today diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index a12ea477c..c6eb7c3ea 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -163,7 +163,7 @@ Verstecken Anheften Anheften - Nicht mehr anheften + Loslösen Archivieren Einblenden Archivierte Chats @@ -228,6 +228,7 @@ ZU EINSTELLUNGEN Profil öffnen Kanal öffnen + Gruppe öffnen Nachricht senden Erwähnen Benachrichtigungen stumm @@ -242,12 +243,14 @@ Keine Ergebnisse Keine Ergebnisse Probiere eine neue Suche. - Musik - Dateien - Links - Sprache - Medien + Musik aus all deinen Chats wird hier angezeigt. + Dateien aus all deinen Chats werden hier angezeigt. + Links aus all deinen Chats werden hier angezeigt. + Sprache aus all deinen Chats wird hier angezeigt. + Medien aus all deinen Chats werden hier angezeigt. Chats + Nachricht angeheftet + Nachricht losgelöst Zum Admin machen Adminrechte bearbeiten @@ -563,6 +566,7 @@ Langsamer Modus ist aktiv, du kannst nicht mehr als eine Nachricht gleichzeitig senden. Langsamer Modus ist aktiv, du kannst nicht mehr Elemente auswählen. Dieser Text ist für eine einzelne Nachricht leider zu lang.\n\nLangsamer Modus ist aktiv, du kannst nicht mehr als eine gleichzeitig senden. + **%1$s** als Admin ernannt Neue Umfrage Neues Quiz @@ -895,10 +899,12 @@ Hier tippen um gespeicherte GIFs zu sehen Anheften Mitglieder benachrichtigen + Auch bei %1$s anheften Loslösen Nachricht anheften Nachricht loslösen - Nachricht in der Gruppe wirklich anheften? + Möchtest du eine ältere Nachricht anheften, während du eine neuere Nachricht angeheftet lässt? + Wirklich diese Nachricht in der Gruppe für alle Mitglieder anheften? Nachricht im Kanal wirklich anheften? Möchtest du diese Nachricht ganz oben im Chat anheften? Angeheftete Nachricht wieder entfernen? @@ -923,6 +929,7 @@ Sonstiges Beschreibung Angeheftete Nachricht + Vorherige Nachricht Angeheftete Umfrage bearbeitet Nachricht bearbeiten @@ -996,7 +1003,7 @@ Tippen für Foto, halten für Video Antippen für Listenansicht Ohne Ton senden - Jetzt senden> + Jetzt senden Umplanen Heute Planen @@ -1041,12 +1048,11 @@ m h w - to private messages and groups - - Transfer Bot Ownership + an private Nachrichten und Gruppen + Bot-Inhaberschaft übertragen Das wird die **vollständigen Eigentümerrechte** des Bots an den ausgewählten Nutzer übertragen. Inhaber ändern - You can transfer bot only if you have: + Nur so kannst du einen Bot übertragen: Kommentar hinterlassen Kommentare Kommentar @@ -1059,7 +1065,11 @@ Thread anzeigen Datum wählen Dieser Chat hilft dir, die Antworten auf deine Kommentare in den Kanälen zu verfolgen. - Sorry, this post has been removed from the discussion group. + Dieser Beitrag wurde leider aus der Diskussionsgruppe entfernt. + ALLE NACHRICHTEN LOSLÖSEN + ANGEHEFTETE NACHRICHTEN VERSTECKEN + Angeheftete Nachrichten versteckt + Neu angeheftete Nachrichten lässt sie erneut erscheinen. %1$s hat den Timer auf %2$s gesetzt Du hast den Timer auf %1$s gesetzt @@ -1175,6 +1185,25 @@ %1$s hat einen Live-Standort angeheftet %1$s hat ein GIF angeheftet %1$s hat Audiodatei angeheftet + %1$s hat \"%2$s\" angeheftet + %1$s hat eine Nachricht angeheftet + %1$s hat eine Umfrage angeheftet %2$s + %1$s hat ein Quiz angeheftet %2$s + %1$s hat ein Bild angeheftet + %1$s hat ein Spiel angeheftet + %1$s hat einen Spielstand angeheftet + %1$s hat ein Video angeheftet + %1$s hat eine Datei angeheftet + %1$s hat eine Rechnung angeheftet + %1$s har einen Sticker angeheftet + %1$s hat einen %2$s-Sticker angeheftet + %1$s hat eine Sprachnachricht angeheftet + %1$s hat eine Videonachricht angeheftet + %1$s hat einen Kontakt angeheftet %2$s + %1$s hat einen Standort angeheftet + %1$s hat einen Live-Standort angeheftet + %1$s hat ein GIF angeheftet + %1$s hat eine Audiodatei angeheftet Telegram Kontakt auswählen @@ -1215,6 +1244,9 @@ Freunde zu Telegram einladen Leute in der Nähe zum Chatten finden Leute über Benutzername finden + Neuer Kontakt + Die Nummer **%1$s** ist nicht in deinen Kontakten. Möchtest du sie hinzufügen? + Kontakt hinzufügen Leute hinzufügen... Mehr Mitglieder kannst du hinzufügen, sobald die Gruppe erstellt wurde. @@ -2310,6 +2342,12 @@ %1$s km entfernt %1$s ft entfernt %1$s mi entfernt + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km %1$sm entfernt %1$skm entfernt %1$sft entfernt @@ -2343,6 +2381,8 @@ gerade aktualisiert Du und %1$s %1$s mit %2$s geteilt + %1$s geteilt mit %2$s + %1$s geteilt mit %2$s ALLE BEENDEN Du teilst deinen Live-Standort mit %1$s Wähle, wie lange %1$s deinen Live-Standort sehen darf. @@ -2371,6 +2411,19 @@ Als Standort festlegen Leute werden deine Gruppe im Bereich \'Leute in der Nähe\" finden können. Orte in der Umgebung + Annäherungsalarm + Hinweis, wenn %1$s innerhalb %2$s ist + Hinweis, wenn jemand innerhalb %1$s ist + Du bist bereits näher als %1$s + Standort teilen + Teilen + Damit der Alarm funktioniert, teile bitte deinen Standort in diesem Chat. + Hinweis, wenn %1$s in der Nähe ist + Alarmieren, wenn andere Mitglieder der Gruppe in der Nähe sind. + Annäherungsalarm gesetzt + Wir benachrichtigen dich, sobald %1$s %2$s von Ihnen dir entfernt ist. + Wir benachrichtigen dich, sobald sich jemand %1$s von dir befindet. + Annäherungsalarm aufgehoben Als Liste Als Gitter @@ -2478,6 +2531,41 @@ Das ist jetzt das Hauptvideo der Gruppe. Bild in Galerie gespeichert Video in Galerie gespeichert + Bild in Downloads gespeichert + Video in Downloads gespeichert + GIF in Downloads gespeichert + Datei in Musik gespeichert + Datei in Downloads gespeichert + %1$d Dateien in Downloads gespeichert + Datei in Downloads gespeichert + %1$d Dateien in Downloads gespeichert + %1$d Dateien in Downloads gespeichert + %1$d Dateien in Downloads gespeichert + %1$d Dateien in Downloads gespeichert + %1$d Bilder in Galerie gespeichert + Bild in Galerie gespeichert + %1$d Bilder in Galerie gespeichert + %1$d Bilder in Galerie gespeichert + %1$d Bilder in Galerie gespeichert + %1$d Bilder in Galerie gespeichert + %1$d Videos in Galerie gespeichert + Video in Galerie gespeichert + %1$d Videos in Galerie gespeichert + %1$d Videos in Galerie gespeichert + %1$d Videos in Galerie gespeichert + %1$d Videos in Galerie gespeichert + %1$d Dateien in Musik gespeichert + Datei in Musik gespeichert + %1$d Dateien in Musik gespeichert + %1$d Dateien in Musik gespeichert + %1$d Dateien in Musik gespeichert + %1$d Dateien in Musik gespeichert + %1$d Objekte in Galerie gespeichert + Ein Objekt in Galerie gespeichert + %1$d Objekte in Galerie gespeichert + %1$d Objekte in Galerie gespeichert + %1$d Objekte in Galerie gespeichert + %1$d Objekte in Galerie gespeichert Zweistufige Bestätigung Zweistufige Bestätigung @@ -2761,6 +2849,9 @@ un1 ist in die Gruppe zurückgekehrt un1 ist der Gruppe beigetreten Du bist in die Gruppe zurückgekehrt + un1 ist jetzt %1$s von dir entfernt + Du befindest dich jetzt innerhalb %1$s von un1 + un1 ist jetzt %1$s von un2 entfernt Du hast diesem Bot erlaubt, dich anzuschreiben, als du dich auf %1$s angemeldet hast. %1$s hat die folgenden Dokumente erhalten: %2$s Persönliche Daten @@ -2937,6 +3028,7 @@ Telegram braucht Zugriff auf die Funktion \'Über andere Apps einblenden\'. Nur so können Videos im Bild in Bild Modus wiedergegeben werden. EINSTELLUNGEN Bitte erlaube Telegram auf dem Sperrbildschirm, damit Anrufe signalisiert werden können. + Um deinen Live-Standort in diesem Chat zu teilen, muss Telegram die ganze Zeit Zugang zu deinem Standort haben, auch während die App im Hintergrund läuft.\n\nWir greifen nur für die von dir gewählte Dauer auf deinen Standort zu und du kannst jederzeit aufhören, ihn zu teilen. Wir werden deinen Standort für keinen anderen Zweck nutzen, als ihn in diesem Chat zu teilen. Wachstum Abonnenten @@ -3010,6 +3102,15 @@ Aktivste Wochentage Nachrichten anzeigen Profil öffnen + Heute + Gestern + Aufrufe + Öffentlich geteilt + Privat geteilt + Statistiken anzeigen + Kanal-Statistiken anzeigen + Nachrichtenstatistik + Nachricht öffnen Telegram Schnell @@ -3244,6 +3345,12 @@ %1$d neue Nachrichten %1$d neue Nachrichten %1$d neue Nachrichten + %1$d Nachrichten losgelöst + Nachricht losgelöst + %1$d Nachrichten losgelöst + %1$d Nachrichten losgelöst + %1$d Nachrichten losgelöst + %1$d Nachrichten losgelöst %1$d Nachrichten %1$d Nachricht %1$d Nachrichten @@ -3400,6 +3507,12 @@ %1$sx geteilt %1$sx geteilt %1$sx geteilt + %1$sx öffentlich geteilt + %1$sx öffentlich geteilt + %1$sx öffentlich geteilt + %1$sx öffentlich geteilt + %1$sx öffentlich geteilt + %1$sx öffentlich geteilt %1$s geteilt %1$s geteilt %1$s geteilt @@ -3611,6 +3724,24 @@ %1$d Kommentare %1$d Kommentare %1$d Kommentare + %1$d Kommentare + %1$d Kommentar + %1$d Kommentare + %1$d Kommentare + %1$d Kommentare + %1$d Kommentare + Kommentare + Kommentar + Kommentare + Kommentare + Kommentare + Kommentare + %1$d angeheftete Nachrichten + Angeheftete Nachricht + %1$d angeheftete Nachrichten + %1$d angeheftete Nachrichten + %1$d angeheftete Nachrichten + %1$d angeheftete Nachrichten Gruppe Kanal @@ -3684,6 +3815,7 @@ Titel Überschrift Mein Standort + Benachrichtigen, wenn Leute, die ihren Standort teilen, in der Nähe sind Videoqualität Seitenverhältnis Nimm ein weiteres Bild auf @@ -3737,6 +3869,7 @@ Zur hinteren Kamera gewechselt Kamera ist an Kamera ist aus + Liste angehefteter Nachrichten MMMM yyyy dd. MMM yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'Heute um\' HH:mm \'erinnern\' \'Am\' d MMM \'um\' HH:mm \'erinnern\' \'Am\' d MMM yyyy \'um\' HH:mm \'erinnern\' - Today diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 43e5476c5..7c3ca4f56 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -228,6 +228,7 @@ IR A AJUSTES Abrir perfil Abrir canal + Abrir grupo Enviar mensaje Mencionar Notificaciones silenciadas @@ -242,12 +243,14 @@ Sin resultados Sin resultados Intenta una nueva búsqueda. - Música - Archivos - Enlaces - Voz - Media + La música de todos tus chats aparecerá aquí. + Los archivos de todos tus chats aparecerán aquí. + Los enlaces de todos tus chats aparecerán aquí. + Los mensajes de voz de todos tus chats aparecerán aquí. + La multimedia de todos tus chats aparecerá aquí. Chats + Mensaje fijado + Mensaje desfijado Promover a administrador Permisos de administrador @@ -560,9 +563,10 @@ %1$dh Elige el tiempo que cada miembro debe esperar antes de enviar su siguiente mensaje. Los miembros podrán enviar sólo un mensaje cada %1$s. - El modo lento está activado. No puedes enviar más de un mensaje a la vez. - El modo lento está activado. No puedes seleccionar más ítems. - Lo sentimos, este texto es muy largo para ser enviado en un mensaje.\n\nEl modo lento está activado. No puedes enviar más de un mensaje a la vez. + El modo lento está activo. No puedes enviar más de un mensaje a la vez. + El modo lento está activo. No puedes seleccionar más ítems. + Lo sentimos, este texto es muy largo para ser enviado en un mensaje.\n\nEl modo lento está activo. No puedes enviar más de un mensaje a la vez. + **%1$s** promovido a administrador Nueva encuesta Nuevo cuestionario @@ -895,10 +899,12 @@ Toca y ve los GIF guardados Fijar Notificar a todos los miembros + Fijar también para %1$s Desfijar Fijar mensaje Desfijar mensaje - ¿Quieres fijar este mensaje en el grupo? + ¿Quieres fijar un mensaje más antiguo y a la vez mantener fijado uno más reciente? + ¿Quieres fijar este mensaje para todos los miembros del grupo? ¿Quieres fijar este mensaje en el canal? ¿Quieres fijar este mensaje en la parte de arriba del chat? ¿Quieres desfijar este mensaje? @@ -923,6 +929,7 @@ Otros Descripción Mensaje fijado + Mensaje anterior Encuesta fijada editado Editar mensaje @@ -992,11 +999,11 @@ ESTAFA vía El mensaje no existe - Modo lento activado. Puedes enviar\ntu próximo mensaje en %1$s. + Modo lento activo. Puedes enviar\ntu próximo mensaje en %1$s. Toca para foto, mantén para video Toca para ver como lista. Enviar sin sonido - Enviar ahora> + Enviar ahora Reprogramar Hoy Programar @@ -1042,7 +1049,6 @@ h S a chats privados y grupos - Transferir propiedad del bot Esto transferirá todos los **derechos de propietario** del bot al usuario elegido. Cambiar propietario @@ -1059,7 +1065,11 @@ Ver hilo Elige una fecha Este chat te ayuda a realizar un seguimiento de las respuestas a tus comentarios en canales. - Sorry, this post has been removed from the discussion group. + Esta publicación ha sido eliminada del grupo de conversación. + DESFIJAR TODOS LOS MENSAJES + OCULTAR MENSAJES FIJADOS + Mensajes fijados ocultos + Verás los mensajes fijados\notra vez si se fija uno nuevo. %1$s activó la autodestrucción en %2$s Activaste la autodestrucción en %1$s @@ -1175,6 +1185,25 @@ %1$s fijó una ubicación en tiempo real %1$s fijó un GIF %1$s fijó un audio + %1$s fijó “%2$s” + %1$s fijó un mensaje + %1$s fijó una encuesta %2$s + %1$s fijó un cuestionario %2$s + %1$s fijó una foto + %1$s fijó un juego + %1$s fijó una puntuación + %1$s fijó un video + %1$s fijó un archivo + %1$s fijó una factura + %1$s fijó un sticker + %1$s fijó un %2$s sticker + %1$s fijó un mensaje de voz + %1$s fijó un videomensaje + %1$s fijó un contacto %2$s + %1$s fijó un mapa + %1$s fijó una ubicación en tiempo real + %1$s fijó un GIF + %1$s fijó un audio Telegram Elige un contacto @@ -1215,6 +1244,9 @@ Invita a tus amigos a probar Telegram Encuentra personas cerca para chatear Busca personas por nombre de usuario + Nuevo contacto + El número de teléfono **%1$s** no está en tu lista de contactos. ¿Quieres añadirlo? + Añadir contacto Añadir personas... Podrás añadir más miembros después de crear el grupo. @@ -1662,7 +1694,7 @@ Estás a punto de aplicar un pack de idioma personalizado (**%1$s**) que está completo en un %2$d%%.\n\nEsto traducirá toda la interfaz. Puedes sugerir correcciones en la [plataforma de traducción].\n\nPuedes cambiar el idioma cuando quieras en Ajustes. Datos insuficientes Idiomas no oficiales - Ese idioma no está. + Idioma no disponible. Ya estás usando este pack de idioma (**%1$s**). Puedes cambiar el idioma cuando quieras en Ajustes. Lamentablemente, este pack de idioma personalizado (**%1$s**) no contiene datos para Telegram Android. Ten en cuenta que el soporte de Telegram está hecho por voluntarios. Respondemos lo antes posible, pero puede tomar tiempo.\n\nPor favor, mira las Preguntas frecuentes de Telegram]]>: tienen respuestas para la mayoría de las preguntas y soluciones a problemas]]>. @@ -2310,6 +2342,12 @@ a %1$s km a %1$s ft a %1$s mi + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km a %1$s m de ti a %1$s km de ti a %1$s ft de ti @@ -2334,7 +2372,7 @@ O elige un lugar Toca para enviar esta ubicación Ubicaciones en tiempo real - Ubicación en tiempo real + En tiempo real 15 minutos 1 hora 8 horas @@ -2343,6 +2381,8 @@ recién actualizada Tú y %1$s %1$s compartida con %2$s + %1$s compartida con %2$s + %1$s compartida con %2$s DETENER TODO Compartiendo tu ubicación en tiempo real con %1$s Elige durante cuánto tiempo %1$s verá tu ubicación exacta. @@ -2371,6 +2411,19 @@ Establecer esta ubicación Las personas podrán encontrar tu grupo en la sección “Personas cerca”. Lugares en esta zona + Aviso de proximidad + Notificar cuando %1$s esté a %2$s + Notificar cuando alguien esté a %1$s + Ya estás a menos de %1$s + Compartir ubicación + Compartir + Para que funcione el aviso, por favor, comparte tu ubicación en tiempo real en este chat. + Avisar cuando %1$s esté cerca + Avisar cuando otros miembros del grupo estén cerca + Aviso de proximidad activo + Te notificaremos cuando %1$s esté a %2$s de ti. + We will notify you once someone is within %1$s from you. + Aviso de proximidad cancelado Mostrar como lista Mostrar como cuadrícula @@ -2478,6 +2531,41 @@ Ahora este es el video principal del grupo. Foto guardada en Galería Video guardado en Galería + Foto guardada en descargas + Video guardado en descargas + GIF guardado en descargas + Archivo guardado en música + Archivo guardado en descargas + %1$d archivos guardados en descargas + Archivo guardado en descargas + %1$d archivos guardados en descargas + %1$d archivos guardados en descargas + %1$d archivos guardados en descargas + %1$d archivos guardados en descargas + %1$d fotos guardadas en galería + Foto guardada en galería + %1$d fotos guardadas en galería + %1$d fotos guardadas en galería + %1$d fotos guardadas en galería + %1$d fotos guardadas en galería + %1$d videos guardados en galería + Video guardado en galería + %1$d videos guardados en galería + %1$d videos guardados en galería + %1$d videos guardados en galería + %1$d videos guardados en galería + %1$d archivos guardados en música + Archivo guardado en música + %1$d archivos guardados en música + %1$d archivos guardados en música + %1$d archivos guardados en música + %1$d archivos guardados en música + %1$d ítems guardados en galería + Ítem guardado en galería + %1$d ítems guardados en galería + %1$d ítems guardados en galería + %1$d ítems guardados en galería + %1$d ítems guardados en galería Verificación en dos pasos Verificación en dos pasos @@ -2761,6 +2849,9 @@ un1 volvió al grupo un1 se unió al grupo Volviste al grupo + un1 ahora está a %1$s de ti + Ahora estás a %1$s de un1 + un1 ahora está a %1$s de un2 Autorizaste que este bot te envíe mensajes cuando iniciaste sesión en %1$s. %1$s recibió los siguientes documentos: %2$s Datos personales @@ -2937,6 +3028,7 @@ Telegram necesita acceso a mostrarse sobre otras aplicaciones para usar el modo imagen en imagen. AJUSTES Por favor, permite a Telegram aparecer en la pantalla bloqueada para que las llamadas funcionen correctamente. + Para compartir tu ubicación en tiempo real en este chat, Telegram necesita acceso a tu ubicación todo el tiempo, incluyendo cuando la app está en segundo plano.\n\nAccederemos a tu ubicación sólo durante el tiempo que elijas, y puedes dejar de compartirla en cualquier momento. No usaremos tu ubicación para ningún otro propósito que no sea el de compartirla en este chat. Crecimiento Seguidores @@ -2957,7 +3049,7 @@ Borrar caché de Telegram Resumen Vistas por post - Comparticiones por post + Reenvíos por post Notificaciones activas Borrar base de datos local "Caché de Telegram • %s " @@ -3010,6 +3102,15 @@ Top días de la semana Ver mensajes Abrir perfil + Hoy + Ayer + Vistas + Reenvíos en público + Reenvíos en privado + Ver estadísticas + Ver estadísticas del canal + Estadísticas del mensaje + Abrir mensaje Telegram Rápida @@ -3244,6 +3345,12 @@ %1$d mensajes nuevos %1$d mensajes nuevos %1$d mensajes nuevos + %1$d mensajes desfijados + mensaje desfijado + %1$d mensajes desfijados + %1$d mensajes desfijados + %1$d mensajes desfijados + %1$d mensajes desfijados %1$d mensajes %1$d mensaje %1$d mensajes @@ -3400,6 +3507,12 @@ %1$s reenvíos %1$s reenvíos %1$s reenvíos + %1$s reenvíos públicos + %1$s reenvío público + %1$s reenvíos públicos + %1$s reenvíos públicos + %1$s reenvíos públicos + %1$s reenvíos públicos %1$s reenvíos %1$s reenvío %1$s reenvíos @@ -3611,6 +3724,24 @@ %1$d comentarios %1$d comentarios %1$d comentarios + %1$d comentarios + %1$d comentario + %1$d comentarios + %1$d comentarios + %1$d comentarios + %1$d comentarios + comentarios + comentario + comentarios + comentarios + comentarios + comentarios + %1$d mensajes fijados + Mensaje fijado + %1$d mensajes fijados + %1$d mensajes fijados + %1$d mensajes fijados + %1$d mensajes fijados Grupo Canal @@ -3684,6 +3815,7 @@ Título Encabezado Mi ubicación + Notificar cuando las personas que comparten su ubicación estén dentro del rango Calidad de video Relación de aspecto Tomar una foto más @@ -3737,6 +3869,7 @@ Cambió a la cámara trasera La cámara está encendida La cámara está apagada + Lista de mensajes fijados MMMM \'de\' yyyy dd MMM yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'Recordar hoy a las\' HH:mm \'Recordar el\' d \'de\' MMM \'a las\' HH:mm \'Recordar el\' d \'de\' MMM \'de\' yyyy \'a las\' HH:mm - Today diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index 7de6b8e48..3e8e66a12 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -228,6 +228,7 @@ VAI ALLE IMPOSTAZIONI Apri profilo Apri canale + Apri gruppo Invia messaggio Menziona Notifiche silenziate @@ -242,12 +243,14 @@ Nessun risultato Nessun risultato Prova una nuova ricerca. - Musica - File - Link - Vocali - Media + La musica da tutte le tue chat apparirà qui. + I file da tutte le tue chat appariranno qui. + I link da tutte le tue chat appariranno qui. + I vocali da tutte le tue chat appariranno qui. + I media da tutte le tue chat appariranno qui. Chat + Messaggio fissato + Messaggio tolto Rendi amministratore Modifica permessi amministratore @@ -283,7 +286,7 @@ un1 ha fissato un contatto un1 ha fissato %1$s un1 ha fissato una posizione - un1 ha fissato una posizione attuale + un1 ha fissato una posizione in tempo reale un1 ha fissato una GIF un1 ha fissato un file audio Questo gruppo è stato aggiornato a supergruppo @@ -413,7 +416,7 @@ %1$s ha pubblicato un sondaggio %2$s %1$s ha pubblicato il quiz \"%2$s\" %1$s ha pubblicato una posizione - %1$s ha pubblicato una posizione attuale + %1$s ha pubblicato una posizione in tempo reale %1$s ha pubblicato un file %1$s ha pubblicato una GIF %1$s ha pubblicato %2$s @@ -441,7 +444,7 @@ Eliminare messaggi altrui Eliminare messaggi Aggiungere amministratori - Invia anonimamente + Inviare anonimamente Rimuovi amministratore Trasferisci proprietà gruppo Trasferisci proprietà canale @@ -558,11 +561,12 @@ %1$ds %1$dm %1$dh - Scegli quanto tempo ciascun membro deve attendere prima di inviare il messaggio successivo. + Scegli quanto dovranno aspettare i membri prima di inviare il messaggio successivo. I membri potranno inviare solo un messaggio ogni %1$s. La modalità lenta è attiva. Non puoi inviare più di un messaggio alla volta. La modalità lenta è attiva. Non puoi selezionare più elementi. Spiacenti, questo testo è troppo lungo da inviare come singolo messaggio.\n\nLa modalità lenta è attiva. Non puoi inviare più di un messaggio alla volta. + **%1$s** promosso ad amministratore Nuovo sondaggio Nuovo quiz @@ -796,11 +800,11 @@ %1$s sta inviando un audio... %1$s sta inviando una foto... APERTURA RAPIDA - APRI GRUPPO + VISUALIZZA GRUPPO VISUALIZZA SFONDO VISUALIZZA TEMA - APRI CANALE - APRI MESSAGGIO + VISUALIZZA CANALE + VISUALIZZA MESSAGGIO Il tema scuro si attiverà automaticamente durante la notte Note %1$s sta giocando a un gioco... @@ -895,10 +899,12 @@ Tocca qui per vedere le GIF salvate Fissa Notifica tutti i membri + Fissa anche per %1$s Togli Fissa messaggio Togli messaggio - Vuoi fissare questo messaggio in questo gruppo? + Vuoi fissare un vecchio messaggio lasciandone fissato uno più recente? + Vuoi fissare questo messaggio per tutti i membri del gruppo? Vuoi fissare questo messaggio in questo canale? Vuoi fissare questo messaggio nella parte superiore della chat? Vuoi togliere questo messaggio? @@ -923,6 +929,7 @@ Altro Descrizione Messaggio fissato + Messaggio precedente Sondaggio fissato modificato Modifica messaggio @@ -956,9 +963,9 @@ Tieni premuto per l\'audio. Tocca per il video. Tieni premuto per il video. Tocca per l\'audio. Scarta messaggio vocale - Sei sicuro di voler arrestare la registrazione e scartare il tuo messaggio vocale? + Sei sicuro di voler terminare la registrazione e scartare il tuo messaggio vocale? Scarta videomessaggio - Sei sicuro di voler arrestare la registrazione e scartare il tuo videomessaggio? + Sei sicuro di voler terminare la registrazione e scartare il tuo videomessaggio? Scarta Gli amministratori di questo gruppo ti hanno vietato di inviare media qui fino al %1$s Gli amministratori di questo gruppo ti hanno vietato di inviare contenuti inline qui fino al %1$s @@ -982,8 +989,8 @@ Cerca sticker in primo piano Cerca emoji URL - Fornitore anteprima mappa - Fornitore anteprima mappa + Anteprima mappa + Anteprima mappa Telegram Google Yandex @@ -996,7 +1003,7 @@ Tocca per le foto, tieni premuto per i video Tocca per vedere come lista. Invia senza suono - Invia ora> + Invia ora Riprogramma Oggi Programma @@ -1041,8 +1048,7 @@ m h S - to private messages and groups - + in chat e gruppi privati Trasferisci proprietà bot Questo trasferirà tutti i **diritti di proprietà** per il bot all\'utente selezionato. Cambia proprietario @@ -1059,7 +1065,11 @@ Visualizza thread Scegli data Questa chat ti aiuta a tenere traccia delle risposte ai tuoi commenti nei canali. - Sorry, this post has been removed from the discussion group. + Spiacenti, questo post è stato rimosso dal gruppo di discussione. + TOGLI TUTTI I MESSAGGI + NASCONDI I MESSAGGI FISSATI + Messaggi fissati nascosti + Rivedrai i messaggi fissati solo se ne sarà fissato uno nuovo. %1$s ha impostato il timer di autodistruzione a %2$s Hai impostato il timer di autodistruzione a %1$s @@ -1082,7 +1092,7 @@ %1$s ti ha inviato un sondaggio %2$s %1$s ti ha inviato il quiz \"%2$s\" %1$s ti ha inviato una posizione - %1$s ti ha inviato una posizione attuale + %1$s ti ha inviato una posizione in tempo reale %1$s ti ha invitato a giocare %2$s %1$s ha totalizzato %3$s a %2$s %1$s ti ha inviato un file @@ -1100,7 +1110,7 @@ %1$s ha inviato il quiz \"%3$s\" nel gruppo %2$s %1$s ha condiviso un contatto %3$s nel gruppo %2$s %1$s ha inviato una posizione nel gruppo %2$s - %1$s ha condiviso una posizione attuale nel gruppo %2$s + %1$s ha condiviso una posizione in tempo reale nel gruppo %2$s %1$s ha invitato il gruppo %2$s a giocare %3$s %1$s ha totalizzato %4$s a %3$s nel gruppo %2$s %1$s ha inviato un file nel gruppo %2$s @@ -1152,7 +1162,7 @@ %1$s ha fissato un videomessaggio nel gruppo %2$s %1$s ha fissato un contatto %3$s nel gruppo %2$s %1$s ha fissato una posizione nel gruppo %2$s - %1$s ha fissato una posizione attuale nel gruppo %2$s + %1$s ha fissato una posizione in tempo reale nel gruppo %2$s %1$s ha fissato una GIF nel gruppo %2$s %1$s ha fissato un file audio nel gruppo %2$s %1$s ha fissato una fattura nel gruppo %2$s @@ -1172,9 +1182,28 @@ %1$s ha fissato un videomessaggio %1$s ha fissato un contatto %2$s %1$s ha fissato una posizione - %1$s ha fissato una posizione attuale + %1$s ha fissato una posizione in tempo reale %1$s ha fissato una GIF %1$s ha fissato un file audio + %1$s ha fissato \"%2$s\" + %1$s ha fissato un messaggio + %1$s ha fissato un sondaggio %2$s + %1$s ha fissato un quiz %2$s + %1$s ha fissato una foto + %1$s ha fissato un gioco + %1$s ha fissato un punteggio + %1$s ha fissato un video + %1$s ha fissato un file + %1$s ha fissato una fattura + %1$s ha fissato uno sticker + %1$s ha fissato uno %2$s sticker + %1$s ha fissato un messaggio vocale + %1$s ha fissato un videomessaggio + %1$s ha fissato un contatto %2$s + %1$s ha fissato una mappa + %1$s ha fissato una posizione in tempo reale + %1$s ha fissato una GIF + %1$s ha fissato un file audio Telegram Seleziona contatto @@ -1215,6 +1244,9 @@ Invita gli amici a provare Telegram Trova persone nelle vicinanze con cui messaggiare Cerca persone tramite username + Nuovo contatto + Il numero di telefono **%1$s** non è tra i tuoi contatti. Vuoi aggiungerlo? + Aggiungi contatto Aggiungi persone... Potrai aggiungere altri membri dopo aver creato il gruppo. @@ -2310,6 +2342,12 @@ distante %1$s km distante %1$s piedi distante %1$s miglia + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km %1$s m da te %1$s km da te %1$s ft da te @@ -2317,15 +2355,15 @@ Indicazioni Nessun luogo trovato Non ci sono risultati per **%1$s** vicino a te. - Invia la mia posizione corrente - Condividi posizione attuale per... - Condividi posizione attuale + Invia la mia posizione attuale + Posizione in tempo reale... + Invia posizione in tempo reale Termina condivisione Termina condivisione posizione - Vuoi interrompere la condivisione della tua posizione attuale con **%1$s**? - Vuoi interrompere la condivisione della tua posizione attuale con **%1$s**? - Vuoi interrompere la condivisione della tua posizione attuale? - Aggiornata in tempo reale + Vuoi terminare la condivisione della posizione in tempo reale con **%1$s**? + Vuoi terminare la condivisione della posizione in tempo reale con **%1$s**? + Vuoi terminare la condivisione della posizione in tempo reale? + Aggiornata mentre ti muovi Invia la posizione selezionata Posizione Luogo @@ -2333,8 +2371,8 @@ distante %1$s O scegli un luogo Tocca per inviare questa posizione - Posizioni attuali - Posizione attuale + Posizioni in tempo reale + Posizione in tempo reale per 15 minuti per 1 ora per 8 ore @@ -2343,10 +2381,12 @@ aggiornata adesso Tu e %1$s %1$s condivisa con %2$s - ARRESTA TUTTO - Stai condividendo la tua posizione attuale in %1$s - Scegli per quanto tempo %1$s vedrà la tua posizione precisa. - Scegli per quanto tempo le persone in questa chat vedranno la tua posizione attuale. + %1$s condivisa con %2$s + %1$s condivisa con %2$s + TERMINA TUTTO + Posizione in tempo reale condivisa con %1$s + Scegli per quanto %1$s vedrà la tua posizione precisa. + Scegli per quanto le persone in questa chat vedranno la tua posizione in tempo reale. Attiva GPS Per favore attiva il tuo GPS per accedere alle funzioni basate sulla posizione. Rendimi visibile @@ -2371,6 +2411,19 @@ Imposta questa posizione Le persone potranno trovare il tuo gruppo nella sezione \"Persone vicine\". Luoghi in quest\'area + Notifica di prossimità + Notifica quando %1$s è a %2$s + Notifica quando qualcuno è a %1$s + Sei già più vicino di %1$s + Condividi posizione + Condividi + Per far funzionare l\'avviso, condividi la posizione in tempo reale in questa chat. + Avvisa quando %1$s è vicino + Avvisa quando gli altri membri del gruppo sono vicini + Notifica di prossimità impostata + Ti notificheremo quando %1$s sarà a %2$s da te. + Ti notificheremo quando qualcuno sarà a %1$s da te. + Notifica di prossimità annullata Mostra come lista Mostra come griglia @@ -2478,6 +2531,41 @@ Questo è ora il video principale del gruppo. Foto salvata nella galleria Video salvato nella galleria + Foto salvata nei download + Video salvato nei download + GIF salvata nei download + File salvato nella musica + File salvato nei download + %1$d file salvati nei download + File salvato nei download + %1$d file salvati nei download + %1$d file salvati nei download + %1$d file salvati nei download + %1$d file salvati nei download + %1$d foto salvate nella galleria + Foto salvata nella galleria + %1$d foto salvate nella galleria + %1$d foto salvate nella galleria + %1$d foto salvate nella galleria + %1$d foto salvate nella galleria + %1$d video salvati nella galleria + Video salvato nella galleria + %1$d video salvati nella galleria + %1$d video salvati nella galleria + %1$d video salvati nella galleria + %1$d video salvati nella galleria + %1$d file salvati nella musica + File salvato nella musica + %1$d file salvati nella musica + %1$d file salvati nella musica + %1$d file salvati nella musica + %1$d file salvati nella musica + %1$d oggetti salvati nella galleria + Un oggetto salvato nella galleria + %1$d oggetti salvati nella galleria + %1$d oggetti salvati nella galleria + %1$d oggetti salvati nella galleria + %1$d oggetti salvati nella galleria Verifica in due passaggi Verifica in due passaggi @@ -2761,6 +2849,9 @@ un1 è tornato nel gruppo un1 si è unito al gruppo Sei tornato nel gruppo + un1 ora è a %1$s da te + Ora sei a %1$s da un1 + un1 ora è a %1$s da un2 Hai permesso a questo bot di scriverti quando ti sei collegato su %1$s. %1$s ha ricevuto i seguenti documenti: %2$s Dettagli personali @@ -2785,7 +2876,7 @@ Il video è scaduto GIF Posizione - Posizione attuale + Posizione in tempo reale Contatto File Sticker @@ -2810,7 +2901,7 @@ Attenzione! Questo **eliminerà tutti i messaggi** in questa chat per **entrambi** i partecipanti. Attenzione! Questo **eliminerà tutti i messaggi** in questa chat. Elimina tutto - Arrestare il caricamento? + Terminare il caricamento? Aggiorna Telegram Spiacenti, la tua app Telegram è obsoleta e non può gestire la richiesta. Per favore aggiorna Telegram. Numero di telefono non valido. Per favore controlla il numero e riprova. @@ -2860,8 +2951,8 @@ Elimina le bozze cloud Sei sicuro di voler eliminare tutte le bozze? Condividere la tua posizione? - Questo invierà la tua posizione corrente al bot. - L\'app non è riuscita a determinare la tua posizione corrente + Questo invierà la tua posizione attuale al bot. + L\'app non è riuscita a determinare la tua posizione attuale Scegli manualmente Questo bot vorrebbe sapere la tua posizione ogni volta che invii una richiesta. Questo può essere usato per fornire risultati specifici in base alla posizione. Condividere il tuo numero di telefono? @@ -2874,7 +2965,7 @@ Chat segreta Sei sicuro di voler iniziare una chat segreta? Sei sicuro di voler annullare la registrazione? - Vuoi arrestare il processo di verifica? + Vuoi terminare il processo di verifica? Sei sicuro di voler eliminare la tua cronologia della chat con **%1$s**? Sei sicuro di voler eliminare la tua cronologia della chat segreta con **%1$s**? Sei sicuro di voler cancellare la cronologia chat di **%1$s**? @@ -2937,6 +3028,7 @@ Telegram deve accedere allo spostamento su altre app per riprodurre i video in modalità PiP. IMPOSTAZIONI Per favore consenti a Telegram di essere visualizzato sulla schermata di blocco in modo che le chiamate possano funzionare correttamente. + Per condividere la posizione in tempo reale in questa chat, Telegram ha bisogno di accedere alla tua posizione in qualsiasi momento, anche quando l\'applicazione è in background.\n\nAccederemo alla tua posizione solo per la durata da te scelta, e potrai smettere di condividerla in qualsiasi momento. Non useremo la tua posizione per nessun altro scopo se non quello di condividerla in questa chat. Crescita Follower @@ -3010,6 +3102,15 @@ Giorni migliori della settimana Visualizza messaggi Apri profilo + Oggi + Ieri + Visualizzazioni + Condivisioni pubbliche + Condivisioni private + Visualizza statistiche + Visualizza statistiche canale + Statistiche messaggio + Apri messaggio Telegram Veloce @@ -3026,7 +3127,7 @@ Inizia a messaggiare Impostazioni account - Usa meno dati per le chiamate + Usa meno dati per chiamare Chiamata in entrata Connetto Scambio chiavi di crittografia @@ -3078,7 +3179,7 @@ L\'app di **%1$s** sta usando un protocollo non compatibile. Deve aggiornare la sua app prima che tu possa chiamarlo. L\'app di **%1$s** non supporta le chiamate. Deve aggiornare la sua app prima che tu possa chiamarlo. Spiacenti, **%1$s** sta usando una vecchia versione di Telegram che non supporta le videochiamate. - Fai una chiamata vocale + Chiamata vocale Per favore valuta la qualità della tua chiamata Telegram Telegram deve accedere al microfono affinché tu possa effettuare chiamate. Telegram deve accedere al tuo microfono e alla tua videocamera affinché tu possa effettuare videochiamate. @@ -3244,6 +3345,12 @@ %1$d nuovi messaggi %1$d nuovi messaggi %1$d nuovi messaggi + %1$d messaggi tolti + messaggio tolto + %1$d messaggi tolti + %1$d messaggi tolti + %1$d messaggi tolti + %1$d messaggi tolti %1$d messaggi %1$d messaggio %1$d messaggi @@ -3400,12 +3507,18 @@ %1$s condivisioni %1$s condivisioni %1$s condivisioni - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared - %1$s shared + %1$s condivisioni pubbliche + %1$s condivisione pubblica + %1$s condivisioni pubbliche + %1$s condivisioni pubbliche + %1$s condivisioni pubbliche + %1$s condivisioni pubbliche + %1$s hanno condiviso + %1$s ha condiviso + %1$s hanno condiviso + %1$s hanno condiviso + %1$s hanno condiviso + %1$s hanno condiviso %1$s set di sticker %1$s set di sticker %1$s set di sticker @@ -3611,6 +3724,24 @@ %1$d commenti %1$d commenti %1$d commenti + %1$d commenti + %1$d commento + %1$d commenti + %1$d commenti + %1$d commenti + %1$d commenti + commenti + commento + commenti + commenti + commenti + commenti + %1$d messaggi fissati + Messaggio fissato + %1$d messaggi fissati + %1$d messaggi fissati + %1$d messaggi fissati + %1$d messaggi fissati Gruppo Canale @@ -3660,7 +3791,7 @@ Ripeti, una Chiudi lettore musicale Riproduzione a velocità doppia - Termina condivisione posizione attuale + Termina condivisione posizione in tempo reale Fotocamera istantanea Pulsante di scatto Cambia fotocamera @@ -3684,6 +3815,7 @@ Titolo Titolo La mia posizione + Notifica quando le persone che condividono la posizione sono nelle vicinanze Qualità video Proporzioni Scatta un\'altra foto @@ -3737,6 +3869,7 @@ Passato a videocamera posteriore La videocamera è accesa La videocamera è spenta + Elenco messaggi fissati MMMM yyyy dd MMM yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'Ricorda oggi alle\' HH:mm \'Ricorda il\' d MMM \'alle\' HH:mm \'Ricorda il\' d MMM yyyy \'alle\' HH:mm - Today diff --git a/TMessagesProj/src/main/res/values-ko/strings.xml b/TMessagesProj/src/main/res/values-ko/strings.xml index 4435d7f10..f4e33927a 100644 --- a/TMessagesProj/src/main/res/values-ko/strings.xml +++ b/TMessagesProj/src/main/res/values-ko/strings.xml @@ -181,7 +181,7 @@ %1$s 동안 끄기 알림 끄기 %1$s 뒤 - 사용 안 함 + 영원히 음소거 해시태그 최근 사람들 @@ -226,28 +226,31 @@ 새로운 대화방을 숨길까요? 연락처 목록에 없는 사용자에게서 새로운 메시지를 많이 받고 계십니다. 해당 대화방에 **자동 알림 끄기**와 **보관**을 적용하시겠습니까? 설정으로 이동 - Open Profile + 프로필 열기 Open Channel - Send Message - Mention + Open Group + 메시지 보내기 + 언급 Notifications muted Notifications muted for %1$s Notifications unmuted - %1$d messages deleted - Message deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted - %1$d messages deleted + 메시지 %1$d 개가 삭제가 되었습니다. + 메시지 %1$d 개가 삭제가 되었습니다. + 메시지 %1$d 개가 삭제가 되었습니다. + 메시지 %1$d 개가 삭제가 되었습니다. + 메시지 %1$d 개가 삭제가 되었습니다. + 메시지 %1$d 개가 삭제가 되었습니다. No Results - No Results - Try a new search. + 결과 없음 + 검색을 다시 해보세요. Music from all your chats will be shown here. Files from all your chats will be shown here. Links from all your chats will be shown here. Voice from all your chats will be shown here. Media from all your chats will be shown here. - Chats + 대화방 + Message pinned + Message unpinned 관리자로 승격 관리자 권한 수정 @@ -441,7 +444,7 @@ 다른 사람의 메시지 삭제 메시지 삭제 새로운 관리자 추가 - Send Anonymously + 익명으로 보내기 관리자 권한 회수 그룹 소유권 넘기기 채널 소유권 넘기기 @@ -532,9 +535,9 @@ 관리자 세우기 %1$s 님을 제한하시면 이 사용자가 관리자에서 제명됩니다. 토론 - View discussion + 토론 보기 논평을 나눌 그룹 대화방을 추가하세요. - 이어진 채널 + 연결된 채널 Select a group chat that will host comments from your channel. 채널에 게시하시는 모든 것이 이 그룹으로 전달됩니다. **%1$s** is selected as the group that hosts comments for your channel. @@ -563,6 +566,7 @@ 저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. 저속 모드가 켜져 있습니다. 항목을 더 선택하실 수 없습니다. 죄송합니다. 이 글은 한 메시지로 치기에 너무 깁니다.\n\n저속 모드가 켜져 있습니다. 한 번에 메시지를 하나 이상 보내실 수 없습니다. + **%1$s** promoted to admin 새로운 설문 새로운 퀴즈 @@ -712,7 +716,7 @@ 메시지 수정 메시지 삭제 관리자 추가 - Send anonymously + 익명으로 보내기 사용자 차단 사용자 추가 제목: %1$s @@ -895,10 +899,12 @@ 저장한 GIF 파일을 보려면 탭하세요. 고정 모든 참가자에게 알리기 + Also pin for %1$s 고정 해제 메시지 고정 메시지 고정 해제 - 그룹에 이 메시지를 고정하시겠습니까? + Do you want to pin an older message while leaving a more recent one pinned? + 그룹에 있는 모든 참가자들에게 이 메시지를 고정하시겠습니까? 채널에 이 메시지를 고정하시겠습니까? 이 메시지를 대화방 위쪽에 고정하시겠습니까? 메시지를 고정 해제하시겠습니까? @@ -923,6 +929,7 @@ 기타 안내 고정된 메시지 + Previous Message 고정된 설문 수정됨 메시지 수정 @@ -996,7 +1003,7 @@ 사진은 짧게, 동영상은 길게 누르세요 목록으로 보려면 누르세요. 소리 없이 보내기 - 지금 보내기> + 지금 보내기 시간 조정하기 오늘 예약 @@ -1042,24 +1049,27 @@ h w to private messages and groups - Transfer Bot Ownership This will transfer the **full owner** rights for the bot to the selected user. Change Owner You can transfer bot only if you have: - Leave a comment - Comments - Comment - Replies - No comments here yet... + 코멘트 남기기 + 코멘트 + 코멘트 보내기 + 답변 + 아직 코멘트가 없습니다... No replies here yet... - View in chat - Send anonymously - Discussion started - View Thread + 대화에서 보기 + 익명으로 보내기 + 토론이 시작되었습니다 + 쓰레드 보기 Choose date This chat helps you keep track of replies to your comments in Channels. Sorry, this post has been removed from the discussion group. + UNPIN ALL MESSAGES + HIDE PINNED MESSAGES + Pinned messages hidden + Pinned messages will be shown again if a new message is pinned. %1$s 님이 자동 삭제 타이머를 %2$s(으)로 맞췄습니다 자동 삭제 타이머를 %1$s(으)로 맞추셨습니다 @@ -1175,6 +1185,25 @@ %1$s 님이 실시간 위치를 고정했습니다 %1$s 님이 GIF를 고정했습니다 %1$s 님이 오디오 파일을 고정했습니다 + %1$s pinned \"%2$s\" + %1$s pinned a message + %1$s pinned a poll %2$s + %1$s pinned a quiz %2$s + %1$s pinned a photo + %1$s pinned a game + %1$s pinned a game score + %1$s pinned a video + %1$s pinned a file + %1$s pinned an invoice + %1$s pinned a sticker + %1$s pinned a %2$s sticker + %1$s pinned a voice message + %1$s pinned a video message + %1$s pinned a contact %2$s + %1$s pinned a map + %1$s pinned a live location + %1$s pinned a GIF + %1$s pinned an audio file 텔레그램 연락처 선택 @@ -1215,6 +1244,9 @@ Invite friends to try Telegram Find people nearby to chat with Search people by username + New contact + The phone number **%1$s** is not in your contact list. Do you want to add it? + Add contact 사람들을 추가하세요... 그룹을 만들고 나서 참가자를 더 추가하실 수 있습니다. @@ -1223,7 +1255,7 @@ 최대 %1$s 죄송합니다. 이 그룹은 이미 가득 찼습니다. 죄송하지만, 대화방이 없어진 모양입니다. - This channel is private. Please join it to continue viewing its content. + 비공개 채널입니다. 대화 내용을 이어 보려면 채널에 들어가 주세요. This group is private. Please join it to continue viewing its content. 채널 들어가기 그룹 들어가기 @@ -2232,13 +2264,13 @@ 읽지 않음 폴더에 추가 폴더에서 제거 - Choose a folder - **%1$s** added to **%2$s** - **%1$s** added to **%2$s** - **%1$s** added to **%2$s** + 폴더를 선택해주세요 + **%2$s** 폴더에 **%1$s** 대화가 추가됨 + **%2$s** 폴더에 **%1$s** 대화가 추가됨 + **%2$s** 폴더에 **%1$s** 대화가 추가됨 **%1$s**을(를) **%2$s**에서 제거했습니다 - **%1$s** removed from **%2$s** - **%1$s** removed from **%2$s** + **%2$s** 폴더에서 **%1$s** 대화가 삭제됨 + **%2$s** 폴더에서 **%1$s** 대화가 삭제됨 Limit reached Sorry, you can\'t add more than 100 chats to a folder. Sorry, you can\'t exclude more than 100 chats from a folder. @@ -2310,6 +2342,12 @@ %1$s km 떨어짐 %1$s ft 떨어짐 %1$s mi 떨어짐 + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km 나에게서 %1$s m 떨어짐 나에게서 %1$s km 떨어짐 나에게서 %1$s ft 떨어짐 @@ -2343,6 +2381,8 @@ 방금 업데이트됨 나와 %1$s 님 %1$s를 %2$s와 공유 중 + %1$s sharing with %2$s + %1$s sharing with %2$s 모두 중단 실시간 위치를 %1$s와 공유하고 있습니다 %1$s 님에게 회원님의 정확한 위치를 얼마 동안 보일지 선택하세요. @@ -2371,6 +2411,19 @@ 이 위치로 설정하기 사람들이 회원님의 그룹을 \"주변 사람\" 섹션에서 찾을 수 있습니다. 지역에 있는 장소 + Proximity alert + Notify when %1$s is within %2$s + Notify when someone is within %1$s + You are already closer than %1$s + Share Location + Share + For the alert to work, please share your live location in this chat. + Alert when %1$s is close + Alert when other members of the group are close + Proximity alert set + We will notify you once %1$s is within %2$s from you. + We will notify you once someone is within %1$s from you. + Proximity alert cancelled 목록으로 보기 그리드로 보기 @@ -2474,10 +2527,45 @@ 앞으로 이것이 회원님의 메인 프로필 동영상입니다. This is the main channel photo now. This is the main channel video now. - This is the main group photo now. - This is the main group video now. + 현재 그룹 대표 사진입니다. + 현재 그룹 대표 영상입니다. Photo saved to gallery Video saved to gallery + Photo saved to downloads + Video saved to downloads + GIF saved to downloads + File saved to music + File saved to downloads + %1$d files saved to downloads + File saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d photos saved to gallery + Photo saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d videos saved to gallery + Video saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d files saved to music + File saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d items saved to gallery + One item saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery 2단계 인증 2단계 인증 @@ -2761,6 +2849,9 @@ un1 님이 그룹에 돌아왔습니다 un1 님이 그룹에 들어왔습니다 그룹에 돌아오셨습니다 + un1 is now within %1$s from you + You are now within %1$s from un1 + un1 is now within %1$s from un2 %1$s에 로그인할 때 이 봇이 회원님에게 메시지를 보내도록 허용하셨습니다. %1$s 님이 다음 서류를 받았습니다: %2$s 개인 신상 명세 @@ -2937,6 +3028,7 @@ 화면속화면 모드로 동영상을 재생하려면 텔레그램에게 다른 앱 위에 그릴 수 있는 권한을 부여하셔야 합니다. 설정 통화가 제대로 실행되도록 텔레그램이 잠금 화면에 나타나는 것을 허용해 주세요. + To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. 성장 팔로워 @@ -2966,50 +3058,59 @@ %s 기타 데이터 Group members New members by source - Members\' primary language + 참가자 주요 언어 Messages Actions - Members - Messages - Viewing Members - Posting Members - %1$d characters - %1$d character - %1$d characters - %1$d characters - %1$d characters - %1$d characters - %1$d deletions - %1$d deletion - %1$d deletions - %1$d deletions - %1$d deletions - %1$d deletions + 참가자 + 메시지 + 읽기 위주 참가자 + 게시 위주 참가자 + %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 bans %1$d ban %1$d bans %1$d bans %1$d bans %1$d bans - %1$d restrictions - %1$d restriction - %1$d restrictions - %1$d restrictions - %1$d restrictions - %1$d restrictions - %1$d invitations - %1$d invitation - %1$d invitations - %1$d invitations - %1$d invitations - %1$d invitations - Top admins - Top members - Top inviters - %s per message + 제한 %1$d 건 + 제한 %1$d 건 + 제한 %1$d 건 + 제한 %1$d 건 + 제한 %1$d 건 + 제한 %1$d 건 + 초대 %1$d건 + 초대 %1$d건 + 초대 %1$d건 + 초대 %1$d건 + 초대 %1$d건 + 초대 %1$d건 + 상위 관리자 + 상위 참가자 + 상위 초대자 + 메시지 당 %s자 Top days of week - View Messages - Open Profile + 메시지 보기 + 프로필 열기 + Today + Yesterday + Views + Public Shares + Private Shares + View Stats + View Channel Stats + Message Statistics + Open Message 텔레그램 눈부신 속도 @@ -3244,6 +3345,12 @@ 새로운 메시지 %1$d개 새로운 메시지 %1$d개 새로운 메시지 %1$d개 + %1$d messages unpinned + message unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned 메시지 %1$d개 메시지 %1$d개 메시지 %1$d개 @@ -3400,6 +3507,12 @@ %1$s회 공유 %1$s회 공유 %1$s회 공유 + %1$s public shares + %1$s public share + %1$s public shares + %1$s public shares + %1$s public shares + %1$s public shares %1$s shared %1$s shared %1$s shared @@ -3593,24 +3706,42 @@ %2$d 중 %1$d 선택함 %2$d 중 %1$d 선택함 %2$d 중 %1$d 선택함 - View %1$d Replies - View %1$d Reply - View %1$d Replies - View %1$d Replies - View %1$d Replies - View %1$d Replies - %1$d Replies - %1$d Reply - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Replies - %1$d Comments - %1$d Comment - %1$d Comments - %1$d Comments - %1$d Comments - %1$d Comments + 답글 %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 comments + %1$d comment + %1$d comments + %1$d comments + %1$d comments + %1$d comments + comments + comment + comments + comments + comments + comments + %1$d Pinned Messages + Pinned Message + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages 그룹 채널 @@ -3684,6 +3815,7 @@ 제목 표제 내 위치 + Notify when people sharing location are in range 동영상 품질 종횡비 사진 한 장 더 찍기 @@ -3737,6 +3869,7 @@ 후면 카메라로 전환되었습니다 카메라가 켜져 있습니다 카메라가 꺼져 있습니다 + Pinned message list yyyy년 MMMM yyyy년 MMM dd일 h:mm a @@ -3765,5 +3898,4 @@ \'오늘\' HH:mm\'에 알리기\' MMM d HH:mm\'에 알리기\' yyyy\'년\' M\'월\' d\'일\' HH:mm\'에 알림\' - Today diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index fc2ad3c21..2abab4219 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -226,8 +226,9 @@ Nieuwe chats verbergen? Je ontvangt veel nieuwe chats van mensen die geen contact van je zijn. Wil je deze chats **automatisch dempen** en **archiveren**? GA NAAR INSTELLINGEN - Open Profile + Profiel openen Open Channel + Open Group Send Message Mention Notifications muted @@ -240,7 +241,7 @@ %1$d messages deleted %1$d messages deleted No Results - No Results + Geen resultaten Try a new search. Muziek Bestanden @@ -248,6 +249,8 @@ Voice from all your chats will be shown here. Media Chats + Message pinned + Message unpinned Promoveren tot beheerder Beheerdersrechten aanpassen @@ -563,6 +566,7 @@ Tempolimiet ingeschakeld. Je kunt niet meer dan 1 bericht tegelijkertijd sturen. Tempolimiet ingeschakeld. Je kunt niet meer dan 1 item selecteren. Sorry, deze tekst is te lang om als 1 bericht te sturen.\n\nTempolimiet is ingeschakeld, je kunt niet meer dan 1 bericht tegelijkertijd sturen. + **%1$s** promoted to admin Nieuwe poll Nieuwe quiz @@ -895,9 +899,11 @@ Tik hier om opgeslagen GIF\'s te bekijken Vastzetten Alle leden informeren + Also pin for %1$s Losmaken Bericht vastzetten Bericht losmaken + Do you want to pin an older message while leaving a more recent one pinned? Wil je dit bericht vastzetten? Wil je dit bericht vastzetten? Wil je dit bericht vastzetten bovenaan de chat? @@ -923,6 +929,7 @@ Overig Beschrijving Vastgezet bericht + Previous Message Vastgezette poll gewijzigd Bericht wijzigen @@ -996,7 +1003,7 @@ Tik voor foto, hou vast voor video Tik om als lijst weer te geven. Stuur zonder geluid - Stuur nu> + Stuur nu Plan opnieuw Vandaag Plannen @@ -1042,7 +1049,6 @@ u w to private messages and groups - Transfer Bot Ownership This will transfer the **full owner** rights for the bot to the selected user. Change Owner @@ -1060,6 +1066,10 @@ Choose date This chat helps you keep track of replies to your comments in Channels. Sorry, this post has been removed from the discussion group. + UNPIN ALL MESSAGES + HIDE PINNED MESSAGES + Pinned messages hidden + Pinned messages will be shown again if a new message is pinned. %1$s heeft de zelfvernietigingstimer ingesteld op %2$s Je hebt de zelfvernietigingstimer ingesteld op %1$s @@ -1175,6 +1185,25 @@ %1$s heeft een live-locatie vastgezet %1$s heeft GIF vastgezet %1$s heeft muziekbestand vastgezet + %1$s pinned \"%2$s\" + %1$s pinned a message + %1$s pinned a poll %2$s + %1$s pinned a quiz %2$s + %1$s pinned a photo + %1$s pinned a game + %1$s pinned a game score + %1$s pinned a video + %1$s pinned a file + %1$s pinned an invoice + %1$s pinned a sticker + %1$s pinned a %2$s sticker + %1$s pinned a voice message + %1$s pinned a video message + %1$s pinned a contact %2$s + %1$s pinned a map + %1$s pinned a live location + %1$s pinned a GIF + %1$s pinned an audio file Telegram Contact kiezen @@ -1215,6 +1244,9 @@ Invite friends to try Telegram Find people nearby to chat with Search people by username + New contact + The phone number **%1$s** is not in your contact list. Do you want to add it? + Add contact Mensen toevoegen Je kan meer leden toevoegen nadat je de groep hebt aangemaakt. @@ -1274,7 +1306,7 @@ Uitnodigen voor Telegram %1$s is nog geen lid, uitnodigen? Nodig uit - BLOCK + Blokkeren BLOCK AND DELETE REPLIES Blokkeer Blokkeer gebruiker @@ -2310,6 +2342,12 @@ %1$s km afstand %1$s voet afstand %1$s mijl afstand + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km %1$s m afstand %1$s km afstand %1$s ft afstand @@ -2343,6 +2381,8 @@ zojuist bijgewerkt Jij en %1$s %1$s aan het delen met %2$s + %1$s sharing with %2$s + %1$s sharing with %2$s ALLES STOPPEN Je deelt je live-locatie met %1$s Kies hoelang je je nauwkeurige locatie met %1$s wilt delen. @@ -2371,6 +2411,19 @@ Stel deze locatie in Mensen kunnen je groep vinden in de \"Mensen Dichtbij\"-sectie Plaatsen in de buurt + Proximity alert + Notify when %1$s is within %2$s + Notify when someone is within %1$s + You are already closer than %1$s + Share Location + Share + For the alert to work, please share your live location in this chat. + Alert when %1$s is close + Alert when other members of the group are close + Proximity alert set + We will notify you once %1$s is within %2$s from you. + We will notify you once someone is within %1$s from you. + Proximity alert cancelled Weergeven als lijst Weergeven als rooster @@ -2478,6 +2531,41 @@ Dit is nu de hoofdgroepsvideo. Photo saved to gallery Video saved to gallery + Photo saved to downloads + Video saved to downloads + GIF saved to downloads + File saved to music + File saved to downloads + %1$d files saved to downloads + File saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d photos saved to gallery + Photo saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d videos saved to gallery + Video saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d files saved to music + File saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d items saved to gallery + One item saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery Twee-staps-verificatie Twee-staps-verificatie @@ -2761,6 +2849,9 @@ un1 is terug in de groep un1 is lid van de groep Je keerde terug naar de groep + un1 is now within %1$s from you + You are now within %1$s from un1 + un1 is now within %1$s from un2 Je hebt deze bot toegestaan je berichten te sturen door in te loggen op %1$s. %1$s heeft de volgende documenten ontvangen: %2$s Persoonlijke gegevens @@ -2937,6 +3028,7 @@ Telegram heeft de toestemming \'over andere apps tekenen\' nodig om video\'s af te spelen in Picture-in-Picture-modus. INSTELLINGEN Sta Telegram toe om weer te kunnen geven op het vergrendelscherm om ervoor te zorgen dat oproepen goed werken. + To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. Groei Volgers @@ -3010,6 +3102,15 @@ Actiefste dagen Berichten weergeven Profiel openen + Vandaag + Gisteren + Views + Public Shares + Private Shares + View Stats + View Channel Stats + Message Statistics + Open Message Telegram Snel @@ -3244,6 +3345,12 @@ %1$d nieuwe berichten %1$d nieuwe berichten %1$d nieuwe berichten + %1$d messages unpinned + message unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned %1$d berichten %1$d bericht %1$d berichten @@ -3400,6 +3507,12 @@ %1$s keer gedeeld %1$s keer gedeeld %1$s keer gedeeld + %1$s public shares + %1$s public share + %1$s public shares + %1$s public shares + %1$s public shares + %1$s public shares %1$s shared %1$s shared %1$s shared @@ -3611,6 +3724,24 @@ %1$d Comments %1$d Comments %1$d Comments + %1$d comments + %1$d comment + %1$d comments + %1$d comments + %1$d comments + %1$d comments + comments + comment + comments + comments + comments + comments + %1$d Pinned Messages + Pinned Message + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages Groep Kanaal @@ -3684,6 +3815,7 @@ Titel Titel Mijn locatie + Notify when people sharing location are in range Videokwaliteit Beelverhouding Nog een foto nemen @@ -3737,6 +3869,7 @@ Overgeschakeld naar de achtercamera De camera staat aan De camera staat uit + Pinned message list MMMM yyyy dd MMM yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'Herinner vandaag om HH:mm \'Herinner op\' d MMM \'om\' HH:mm \'Herinner op\' d MMM yyyy \'om\' HH:mm - Today diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index dfc26bf75..c54ad83e5 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -228,6 +228,7 @@ ABRIR CONFIGURAÇÕES Abrir Perfil Abrir Canal + Abrir Grupo Enviar Mensagem Mencionar Notificações silenciadas @@ -242,12 +243,14 @@ Sem Resultados Sem Resultados Tente uma nova busca. - Músicas - Arquivos - Links - Voz - Mídias + Músicas de todos os seus chats aparecerão aqui. + Arquivos de todos os seus chats aparecerão aqui. + Links de todos os seus chats aparecerão aqui. + Voz de todos os seus chats aparecerão aqui. + Mídias de todos os seus chats aparecerão aqui. Chats + Mensagem fixada + Mensagem desafixada Promover a administrador Editar permissões de admin @@ -368,7 +371,7 @@ Vídeo do canal alterado Foto do canal removida Nome do canal alterado para un2 - Desculpe, você reservou muitos nomes públicos. Você pode remover o link público de um de seus grupos ou canais, ou criar de forma privada. + Desculpe, você reservou muitos nomes públicos. Você pode remover o link público de um dos seus grupos ou canais, ou criar de forma privada. Dono Administrador Admin @@ -563,6 +566,7 @@ O Modo Lento está ativado. Você não pode enviar mais de uma mensagem por vez. O Modo Lento está ativado. Você não pode selecionar mais itens. Desculpe, este texto é muito longo para ser enviado em uma só mensagem.\n\nO Modo Lento está ativado. Você não pode enviar mais de uma mensagem por vez. + **%1$s** promovido a admin Nova Enquete Novo Quiz @@ -895,12 +899,14 @@ Toque aqui para acessar os GIFs salvos Fixar Notificar todos os membros + Fixar para %1$s também Desafixar Fixar mensagem Desafixar mensagem - Deseja fixar essa mensagem no grupo? + Deseja fixar uma mensagem mais antiga enquanto deixa a mais recente fixada? + Deseja fixar a mensagem para todos os membros do grupo? Deseja fixar essa mensagem no canal? - Deseja fixar essa mensagem no topo do seu chat de Mensagens Salvas? + Deseja fixar essa mensagem no topo do chat? Deseja desafixar essa mensagem? Banir usuário Denunciar spam @@ -923,6 +929,7 @@ Outro Descrição Mensagem fixada + Mensagem Anterior Enquete fixada editada Editar Mensagem @@ -996,7 +1003,7 @@ Toque para foto, segure para vídeo Toque para ver em lista. Enviar sem som - Enviar Agora> + Enviar Agora Reagendar Hoje Agendar @@ -1042,14 +1049,13 @@ h S para mensagens privadas e grupos - Transferir Posse do Bot Isso vai transferir todos os direitos de **dono** do bot para o usuário selecionado. Alterar Dono Você pode transferir este bot somente se tiver: Deixe um comentário Comentários - Comentário + Comentar Respostas Nenhum comentário ainda... Nenhuma resposta ainda... @@ -1059,7 +1065,11 @@ Ver Tópico Escolher data Este chat te ajuda a acompanhar as respostas aos comentários que você fez nos canais. - Sorry, this post has been removed from the discussion group. + Desculpe, esse post foi removido do grupo de conversa. + DESAFIXAR TUDO + OCULTAR MENSAGENS FIXADAS + Mensagens fixadas ocultadas + As mensagens fixadas só aparecerão de novo se uma nova mensagem for fixada. "%1$s alterou o timer de autodestruição para %2$s " Você alterou o timer de autodestruição para %1$s @@ -1175,6 +1185,25 @@ %1$s fixou uma localização em tempo real %1$s fixou um GIF %1$s fixou um arquivo de áudio + %1$s fixou \"%2$s\" + %1$s fixou uma mensagem + %1$s fixou a enquete %2$s + %1$s fixou o quiz %2$s + %1$s fixou uma foto + %1$s fixou um jogo + %1$s fixou uma pontuação de jogo + %1$s fixou um vídeo + %1$s fixou um arquivo + %1$s fixou uma fatura + %1$s fixou um sticker + %1$s fixou o sticker %2$s + %1$s fixou uma mensagem de voz + %1$s fixou uma mensagem de vídeo + %1$s fixou o contato %2$s + %1$s fixou um mapa + %1$s fixou uma localização ao vivo + %1$s fixou um GIF + %1$s fixou um arquivo de áudio Telegram Selecione um Contato @@ -1213,8 +1242,11 @@ Número de telefone Você ainda não tem contatos no Telegram Convide amigos para testar o Telegram - Encontre pessoas próximas para conversar + Encontre pessoas próximas Busque pessoas por nome de usuário + Novo contato + O número de **%1$s** não está nos seus contatos. Deseja adicionar? + Adicionar contato Adicionar pessoas... Você poderá adicionar mais membros depois de criar o grupo. @@ -2310,6 +2342,12 @@ %1$s km de distância %1$s pés de distância %1$s milhas de distância + %1$s pés + %1$s mi + mi + km + %1$s m + %1$s km %1$s m de você %1$s km de você %1$s pés de você @@ -2343,6 +2381,8 @@ atualizado agora Você e %1$s %1$s com %2$s + %1$s com %2$s + %1$s com %2$s PARAR TODOS Compartilhando a Localização com %1$s Escolha por quanto tempo %1$s verá sua localização precisa. @@ -2371,6 +2411,19 @@ Definir esta localização As pessoas poderão encontrar seu grupo na seção \"Pessoas Próximas\". Lugares por aqui + Alerta de proximidade + Notificar quando %1$s estiver a %2$s + Notificar quando alguém estiver a %1$s + Você já está mais perto que %1$s + Compartilhar Localização + Compartilhar + Para o alerta funcionar, compartilhe a sua localização em tempo real neste chat. + Alertar quando %1$s estiver perto + Alertar quando outros participantes estiverem perto + Alerta de proximidade ativado + Vamos te notificar quando %1$s estiver a %2$s de você. + We will notify you once someone is within %1$s from you. + Alerta de proximidade cancelado Exibir em lista Exibir em grade @@ -2478,6 +2531,41 @@ Este é o vídeo principal do grupo agora. Foto salva na galeria Vídeo salvo na galeria + Foto salva em downloads + Vídeo salvo em downloads + GIF salvo em downloads + Arquivo salvo nas músicas + Arquivo salvo em downloads + %1$d arquivos salvos em downloads + Arquivo salvo em downloads + %1$d arquivos salvos em downloads + %1$d arquivos salvos em downloads + %1$d arquivos salvos em downloads + %1$d arquivos salvos em downloads + %1$d fotos salvas na galeria + Foto salva na galeria + %1$d fotos salvas na galeria + %1$d fotos salvas na galeria + %1$d fotos salvas na galeria + %1$d fotos salvas na galeria + %1$d vídeos salvos na galeria + Vídeo salvo na galeria + %1$d vídeos salvos na galeria + %1$d vídeos salvos na galeria + %1$d vídeos salvos na galeria + %1$d vídeos salvos na galeria + %1$d arquivos salvos nas músicas + Arquivo salvo nas músicas + %1$d arquivos salvos nas músicas + %1$d arquivos salvos nas músicas + %1$d arquivos salvos nas músicas + %1$d arquivos salvos nas músicas + %1$d itens salvos na galeria + Um item salvo na galeria + %1$d itens salvos na galeria + %1$d itens salvos na galeria + %1$d itens salvos na galeria + %1$d itens salvos na galeria Verificação em Duas Etapas Verificação em Duas Etapas @@ -2761,6 +2849,9 @@ un1 retornou ao grupo un1 entrou no grupo Você retornou ao grupo + un1 está a %1$s de você + Você está a %1$s de un1 + un1 está agora a %1$s de un2 Você permitiu que o bot te envie mensagens ao fazer o login em %1$s. %1$s recebeu os seguintes documentos: %2$s Dados pessoais @@ -2863,7 +2954,7 @@ Isso irá enviar sua localização atual ao bot. O app não conseguiu determinar a sua localização atual. Escolher manualmente - Esse bot gostaria de saber sua localização todas as vezes que você enviá-lo uma mensagem. Isso pode ser utilizado para providenciar resultados específicos de localização. + Este bot gostaria de saber a sua localização sempre que você o usar. Isso pode ser utilizado para mostrar resultados baseados em localização. Compartilhar seu número de telefone? O bot saberá seu número de telefone. Isso pode ser útil para a integração com outros serviços. Deseja compartilhar o seu número de telefone %1$s com **%2$s**? @@ -2937,6 +3028,7 @@ Para reproduzir vídeos no modo PiP, o Telegram precisa de acesso para aparecer sobre outros apps. CONFIGURAÇÕES Por favor, permita que o Telegram seja mostrado na tela de bloqueio para que as chamadas possam funcionar corretamente. + Para enviar a sua localização em tempo real neste chat, o Telegram precisa de acesso contínuo à sua localização, inclusive enquanto o app estiver em segundo plano.\n\nO Telegram acessará a sua localização somente pela duração que você escolher e você pode parar de compartilhar a qualquer momento. Não usaremos a sua localização para nenhum outro motivo além de compartilhar neste chat. Crescimento Inscritos @@ -3010,6 +3102,15 @@ Dias da semana Ver Mensagens Ver Perfil + Hoje + Ontem + Visualizações + Compartilhamentos Públicos + Compartilhamentos Privados + Ver Estatísticas + Ver Estatísticas do Canal + Estatísticas da Mensagem + Abrir Mensagem Telegram Rápido @@ -3244,6 +3345,12 @@ %1$d novas mensagens %1$d novas mensagens %1$d novas mensagens + %1$d mensagens desafixadas + mensagem desafixada + %1$d mensagens desafixadas + %1$d mensagens desafixadas + %1$d mensagens desafixadas + %1$d mensagens desafixadas %1$d mensagens %1$d mensagem %1$d mensagens @@ -3400,6 +3507,12 @@ %1$s compartilhamentos %1$s compartilhamentos %1$s compartilhamentos + %1$s compartilhamentos públicos + %1$s compartilhamento público + %1$s compartilhamentos públicos + %1$s compartilhamentos públicos + %1$s compartilhamentos públicos + %1$s compartilhamentos públicos %1$s compartilhados %1$s compartilhado %1$s compartilhados @@ -3611,6 +3724,24 @@ %1$d Comentários %1$d Comentários %1$d Comentários + %1$d comentários + %1$d comentário + %1$d comentários + %1$d comentários + %1$d comentários + %1$d comentários + comentários + comentário + comentários + comentários + comentários + comentários + %1$d Mensagens Fixadas + Mensagem Fixada + %1$d Mensagens Fixadas + %1$d Mensagens Fixadas + %1$d Mensagens Fixadas + %1$d Mensagens Fixadas Grupo Canal @@ -3684,6 +3815,7 @@ Título Cabeçalho Minha localização + Notificar quando pessoas que compartilham a localização estiverem perto Qualidade do vídeo Proporção da imagem Tirar mais uma foto @@ -3737,6 +3869,7 @@ Alternou para a câmera traseira Câmera ligada Câmera desligada + Lista de mensagens fixadas MMMM \'de\' yyyy dd \'de\' MMM \'de\' yyyy, h:mm a @@ -3765,5 +3898,4 @@ \'Lembrar hoje às\' HH:mm \'Lembrar em\' d \'de\' MMM \'às\' HH:mm \'Lembrar em\' d \'de\' MMM \'de\' yyyy \'às\' HH:mm - Today diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index c171d42c2..2d518a831 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -249,6 +249,8 @@ Voice from all your chats will be shown here. Media from all your chats will be shown here. Chats + Message pinned + Message unpinned Promote to admin Edit admin rights @@ -564,6 +566,7 @@ Slow Mode is enabled. You can\'t send more than one message at once. Slow Mode is enabled. You can\'t select more items. Sorry, this text is too long to send as one message.\n\nSlow Mode is enabled. You can\'t send more than one message at once. + **%1$s** promoted to admin New Poll New Quiz @@ -896,10 +899,12 @@ Tap here to access saved GIFs Pin Notify all members + Also pin for %1$s Unpin Pin message Unpin message - Do you want to pin this message in this group? + Do you want to pin an older message while leaving a more recent one pinned? + Do you want to pin this message for all members in the group? Do you want to pin this message in this channel? Do you want to pin this message at the top of the chat? Do you want to unpin this message? @@ -924,6 +929,7 @@ Other Description Pinned Message + Previous Message Pinned poll edited Edit Message @@ -997,7 +1003,7 @@ Tap for photo, hold for video Tap to view as a list. Send without sound - Send Now> + Send Now Reschedule Today Schedule @@ -1043,7 +1049,6 @@ h w to private messages and groups - Shares Transfer Bot Ownership This will transfer the **full owner** rights for the bot to the selected user. Change Owner @@ -1061,6 +1066,10 @@ Choose date This chat helps you keep track of replies to your comments in Channels. Sorry, this post has been removed from the discussion group. + UNPIN ALL MESSAGES + HIDE PINNED MESSAGES + Pinned messages hidden + You will see the bar with pinned messages only if a new message is pinned. %1$s set the self-destruct timer to %2$s You set the self-destruct timer to %1$s @@ -1176,6 +1185,25 @@ %1$s pinned a live location %1$s pinned a GIF %1$s pinned an audio file + %1$s pinned \"%2$s\" + %1$s pinned a message + %1$s pinned a poll %2$s + %1$s pinned a quiz %2$s + %1$s pinned a photo + %1$s pinned a game + %1$s pinned a game score + %1$s pinned a video + %1$s pinned a file + %1$s pinned an invoice + %1$s pinned a sticker + %1$s pinned a %2$s sticker + %1$s pinned a voice message + %1$s pinned a video message + %1$s pinned a contact %2$s + %1$s pinned a map + %1$s pinned a live location + %1$s pinned a GIF + %1$s pinned an audio file Telegram Select Contact @@ -2314,6 +2342,12 @@ %1$s km away %1$s ft away %1$s mi away + %1$s ft + %1$s mi + mi + km + %1$s m + %1$s km %1$s m from you %1$s km from you %1$s ft from you @@ -2347,6 +2381,8 @@ updated just now You and %1$s %1$s sharing with %2$s + %1$s sharing with %2$s + %1$s sharing with %2$s STOP ALL You are sharing your Live Location with %1$s Choose for how long %1$s will see your accurate location. @@ -2375,6 +2411,19 @@ Set this location People will be able to find your group in the \"People Nearby\" section. Places in this area + Proximity alert + Notify when %1$s is within %2$s + Notify when someone is within %1$s + You are already closer than %1$s + Share Location + Share + For the alert to work, please share your live location in this chat. + Alert when %1$s is close + Alert when other members of the group are close + Proximity alert set + We will notify you once %1$s is within %2$s from you. + We will notify you once someone is within %1$s from you. + Proximity alert cancelled Show as list Show as grid @@ -2482,6 +2531,41 @@ This is the main group video now. Photo saved to gallery Video saved to gallery + Photo saved to downloads + Video saved to downloads + GIF saved to downloads + File saved to music + File saved to downloads + %1$d files saved to downloads + File saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d files saved to downloads + %1$d photos saved to gallery + Photo saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d photos saved to gallery + %1$d videos saved to gallery + Video saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d videos saved to gallery + %1$d files saved to music + File saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d files saved to music + %1$d items saved to gallery + An item saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery + %1$d items saved to gallery Two-Step Verification Two-Step Verification @@ -2765,6 +2849,9 @@ un1 returned to the group un1 joined the group You returned to the group + un1 is now within %1$s from you + You are now within %1$s from un1 + un1 is now within %1$s from un2 You allowed this bot to message you when you logged in on %1$s. %1$s received the following documents: %2$s Personal details @@ -2941,6 +3028,7 @@ Telegram needs access to draw above other apps to play videos in Picture-in-Picture mode. SETTINGS Please allow Telegram to be shown on the lock screen so that calls can work properly. + To share your live location in this chat, Telegram needs access to your location all the time, including while the app is in the background.\n\nWe will access your location only for the duration you choose, and you can stop sharing it any time. We won\'t use your location for any purpose other than sharing it in this chat. Growth Followers @@ -3014,6 +3102,15 @@ Top days of week View Messages Open Profile + Today + Yesterday + Views + Public Shares + Private Shares + View Stats + View Channel Stats + Message Statistic + Open Message Telegram Fast @@ -3248,6 +3345,12 @@ %1$d new messages %1$d new messages %1$d new messages + %1$d messages unpinned + Message unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned + %1$d messages unpinned %1$d messages %1$d message %1$d messages @@ -3404,6 +3507,12 @@ %1$s shares %1$s shares %1$s shares + %1$s public shares + %1$s public share + %1$s public shares + %1$s public shares + %1$s public shares + %1$s public shares %1$s shared %1$s shared %1$s shared @@ -3621,6 +3730,18 @@ %1$d comments %1$d comments %1$d comments + comments + comment + comments + comments + comments + comments + %1$d Pinned Messages + Pinned Message + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages + %1$d Pinned Messages Group Channel @@ -3694,6 +3815,7 @@ Title Heading My location + Notify when in range Video quality Aspect ratio Take one more picture @@ -3747,6 +3869,7 @@ Switched to rear camera Camera is on Camera is off + Pinned messages list MMM yyyy MMM dd yyyy, h:mm a @@ -3775,6 +3898,4 @@ \'Remind today at\' HH:mm \'Remind on\' MMM d \'at\' HH:mm \'Remind on\' MMM d yyyy \'at\' HH:mm - Today - Yesterday