From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: alina sireneva <alina@tei.su>
Date: Sun, 12 Apr 2026 23:42:54 +0300
Subject: move the voice record button into attachments drawer

---
 .../java/org/telegram/ui/ChatActivity.java    | 43 +++++++----
 .../ui/Components/ChatActivityEnterView.java  | 73 ++++++++++++++++---
 .../ui/Components/ChatAttachAlert.java        |  2 +-
 .../ui/Components/InstantCameraView.java      |  5 +-
 4 files changed, 93 insertions(+), 30 deletions(-)

diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
index 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java
@@ -13140,15 +13140,33 @@ public class ChatActivity extends BaseFragment implements
     }
 
     private void showMediaBannedHint() {
-        if (getParentActivity() == null || currentChat == null && userInfo == null || fragmentView == null || mediaBanTooltip != null && mediaBanTooltip.getVisibility() == View.VISIBLE) {
-            return;
-        }
         SizeNotifierFrameLayout frameLayout = contentView;
         int index = frameLayout.indexOfChild(chatInputViewsContainer);
         if (index == -1) {
             return;
         }
 
+        HintView mediaBanTooltip = inu_makeMediaBannedHint(
+            chatActivityEnterView.isInVideoMode(),
+            frameLayout,
+            index + 1
+        );
+        if (mediaBanTooltip == null) return;
+
+        View sendBtn = chatActivityEnterView.getSendButton();
+        View audioVideoBtn = chatActivityEnterView.getAudioVideoButtonContainer();
+        View viewForTooltip = sendBtn;
+        if (sendBtn.getAlpha() < audioVideoBtn.getAlpha()) {
+            viewForTooltip = audioVideoBtn;
+        }
+        mediaBanTooltip.showForView(viewForTooltip, true);
+    }
+
+    public HintView inu_makeMediaBannedHint(boolean isInVideoMode, FrameLayout attachToView, int attachIndex) {
+        if (getParentActivity() == null || currentChat == null && userInfo == null || fragmentView == null || mediaBanTooltip != null && mediaBanTooltip.getVisibility() == View.VISIBLE) {
+            return null;
+        }
+
         try {
             fragmentView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP, HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
         } catch (Exception e) {
@@ -13158,16 +13176,16 @@ public class ChatActivity extends BaseFragment implements
         if (mediaBanTooltip == null) {
             mediaBanTooltip = new HintView(getParentActivity(), 9, themeDelegate);
             mediaBanTooltip.setVisibility(View.GONE);
-            frameLayout.addView(mediaBanTooltip, index + 1, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0));
+            attachToView.addView(mediaBanTooltip, attachIndex, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0));
         }
 
         if (userInfo != null && userInfo.voice_messages_forbidden) {
-            mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(chatActivityEnterView.isInVideoMode() ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, currentUser.first_name)));
+            mediaBanTooltip.setText(AndroidUtilities.replaceTags(LocaleController.formatString(isInVideoMode ? R.string.VideoMessagesRestrictedByPrivacy : R.string.VoiceMessagesRestrictedByPrivacy, currentUser.first_name)));
         } else if (!ChatObject.canSendVoice(currentChat) && !ChatObject.canSendRoundVideo(currentChat)) {
             if (checkCanRemoveRestrictionsByBoosts()) {
-                return;
+                return null;
             }
-            if (chatActivityEnterView.isInVideoMode()) {
+            if (isInVideoMode) {
                 mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_ROUND));
             } else {
                 mediaBanTooltip.setText(ChatObject.getRestrictedErrorText(currentChat, ChatObject.ACTION_SEND_VOICE));
@@ -13180,7 +13198,7 @@ public class ChatActivity extends BaseFragment implements
             mediaBanTooltip.setText(LocaleController.getString(R.string.GlobalAttachMediaRestricted));
         } else {
             if (currentChat.banned_rights == null) {
-                return;
+                return null;
             }
             if (AndroidUtilities.isBannedForever(currentChat.banned_rights)) {
                 mediaBanTooltip.setText(LocaleController.getString(R.string.AttachMediaRestrictedForever));
@@ -13188,14 +13206,7 @@ public class ChatActivity extends BaseFragment implements
                 mediaBanTooltip.setText(LocaleController.formatString("AttachMediaRestricted", R.string.AttachMediaRestricted, LocaleController.formatDateForBan(currentChat.banned_rights.until_date)));
             }
         }
-
-        View sendBtn = chatActivityEnterView.getSendButton();
-        View audioVideoBtn = chatActivityEnterView.getAudioVideoButtonContainer();
-        View viewForTooltip = sendBtn;
-        if (sendBtn.getAlpha() < audioVideoBtn.getAlpha()) {
-            viewForTooltip = audioVideoBtn;
-        }
-        mediaBanTooltip.showForView(viewForTooltip, true);
+        return mediaBanTooltip;
     }
 
     private void showNoSoundHint() {
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 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java
@@ -224,6 +224,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 
+import desu.inugram.helpers.chat.VoiceRecorderHelper;
 import me.vkryl.android.animator.BoolAnimator;
 import me.vkryl.android.animator.FactorAnimator;
 
@@ -608,7 +609,7 @@ public class ChatActivityEnterView extends FrameLayout implements
     private boolean botKeyboardViewVisible;
     private TimerView recordTimerView;
     private FrameLayout audioVideoButtonContainer;
-    private boolean audioVideoButtonContainerForbidden;
+    public boolean audioVideoButtonContainerForbidden;
     private ChatActivityEnterViewAnimatedIconView audioVideoSendButton;
     private boolean isInVideoMode;
     @Nullable
@@ -891,6 +892,10 @@ public class ChatActivityEnterView extends FrameLayout implements
             if (delegate == null || parentActivity == null) {
                 return;
             }
+            if (VoiceRecorderHelper.interceptForCameraChoice(ChatActivityEnterView.this)) {
+                recordAudioVideoRunnableStarted = false;
+                return;
+            }
             delegate.onPreAudioVideoRecord();
             calledRecordRunnable = true;
             recordAudioVideoRunnableStarted = false;
@@ -2751,6 +2756,7 @@ public class ChatActivityEnterView extends FrameLayout implements
             attachLayout.setEnabled(false);
             attachLayout.setClipChildren(false);
             messageEditTextContainer.addView(attachLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, DEFAULT_HEIGHT, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, DEFAULT_HEIGHT, 0));
+            attachLayout.setTranslationX(VoiceRecorderHelper.attachTranslationXOffset());
 
             notifyButton = new ImageView(context);
             notifySilentDrawable = new CrossOutDrawable(context, R.drawable.input_notify_on, Theme.key_glass_defaultIcon);
@@ -2794,7 +2800,9 @@ public class ChatActivityEnterView extends FrameLayout implements
             attachButton.setColorFilter(new PorterDuffColorFilter(getThemedColor(Theme.key_glass_defaultIcon), PorterDuff.Mode.MULTIPLY));
             attachButton.setImageResource(R.drawable.msg_input_attach2);
             attachButton.setBackground(Theme.createSelectorDrawable(getThemedColor(Theme.key_listSelector)));
-            messageEditTextContainer.addView(attachButton, LayoutHelper.createFrame(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Gravity.BOTTOM | Gravity.RIGHT));
+            if (!VoiceRecorderHelper.isMovedToAttach()) {
+                messageEditTextContainer.addView(attachButton, LayoutHelper.createFrame(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Gravity.BOTTOM | Gravity.RIGHT));
+            }
             attachButton.setOnClickListener(v -> {
                 if (adjustPanLayoutHelper != null && adjustPanLayoutHelper.animationInProgress() || attachLayoutPaddingAlpha == 0f) {
                     return;
@@ -2931,15 +2939,32 @@ public class ChatActivityEnterView extends FrameLayout implements
         };
         sendButtonContainer.setClipChildren(false);
         sendButtonContainer.setClipToPadding(false);
-        textFieldContainer.addView(sendButtonContainer, LayoutHelper.createFrame(100, DEFAULT_HEIGHT, Gravity.BOTTOM | Gravity.RIGHT));
+        textFieldContainer.addView(sendButtonContainer, LayoutHelper.createFrame(VoiceRecorderHelper.isMovedToAttach() ? DEFAULT_HEIGHT : 100, DEFAULT_HEIGHT, Gravity.BOTTOM | Gravity.RIGHT));
+        if (VoiceRecorderHelper.isMovedToAttach() && attachButton != null) {
+            sendButtonContainer.addView(attachButton, LayoutHelper.createFrame(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Gravity.RIGHT | Gravity.BOTTOM));
+        }
 
         audioVideoButtonContainer = new FrameLayout(context) {
 
             @Override
             public void setVisibility(int visibility) {
+                if (visibility == VISIBLE && VoiceRecorderHelper.isMovedToAttach() && !recordingAudioVideo) {
+                    visibility = GONE;
+                }
                 super.setVisibility(visibility);
             }
 
+            @Override
+            public void setAlpha(float alpha) {
+                if (VoiceRecorderHelper.isMovedToAttach() && !recordingAudioVideo) {
+                    alpha = 0f;
+                    if (getVisibility() == VISIBLE) {
+                        super.setVisibility(GONE);
+                    }
+                }
+                super.setAlpha(alpha);
+            }
+
             @Override
             public boolean onInterceptTouchEvent(MotionEvent ev) {
                 if (isLiveComment) return false;
@@ -3211,6 +3236,7 @@ public class ChatActivityEnterView extends FrameLayout implements
             }
         };
         audioVideoButtonContainer.setSoundEffectsEnabled(false);
+        audioVideoButtonContainer.setVisibility(VISIBLE); // trigger inu override for initial state
         sendButtonContainer.addView(audioVideoButtonContainer, LayoutHelper.createFrame(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Gravity.RIGHT | Gravity.BOTTOM));
         audioVideoButtonContainer.setFocusable(true);
         audioVideoButtonContainer.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
@@ -3652,7 +3678,7 @@ public class ChatActivityEnterView extends FrameLayout implements
             public void setTranslationX(float translationX) {
                 innerTranslationX = translationX;
                 super.setTranslationX(
-                    dp(-DEFAULT_HEIGHT) +
+                    dp(-DEFAULT_HEIGHT) + VoiceRecorderHelper.attachTranslationXOffset() +
                     innerTranslationX + attachLayoutPaddingTranslationX + attachLayoutTranslationX +
                     dp(giftButton != null && giftButton.getVisibility() == View.VISIBLE ? -DEFAULT_HEIGHT : 0) * (giftButton == null ? 0 : giftButton.getAlpha()) +
                     dp(botButton != null && botButton.getVisibility() == VISIBLE ? -DEFAULT_HEIGHT : 0) * (botButton == null ? 0 : botButton.getAlpha())
@@ -3911,6 +3937,7 @@ public class ChatActivityEnterView extends FrameLayout implements
         expandStickersButton = new ImageView(getContext()) {
             @Override
             public void setAlpha(float alpha) {
+                if (VoiceRecorderHelper.isMovedToAttach()) alpha = 0f;
                 super.setAlpha(alpha);
                 if (audioVideoButtonContainer != null) {
                     audioVideoButtonContainer.invalidate();
@@ -3919,6 +3946,7 @@ public class ChatActivityEnterView extends FrameLayout implements
 
             @Override
             public void setVisibility(int visibility) {
+                if (VoiceRecorderHelper.isMovedToAttach()) visibility = GONE;
                 super.setVisibility(visibility);
                 if (audioVideoButtonContainer != null) {
                     audioVideoButtonContainer.invalidate();
@@ -4567,7 +4595,9 @@ public class ChatActivityEnterView extends FrameLayout implements
             messageTextTranslationX = offset;
             updateMessageTextParams();
         }
-        attachButton.setTranslationX(attachLayoutPaddingTranslationX + attachLayoutTranslationX + offset);
+        if (!VoiceRecorderHelper.isMovedToAttach()) {
+            attachButton.setTranslationX(attachLayoutPaddingTranslationX + attachLayoutTranslationX + offset);
+        }
         audioVideoSendButton.setTranslationX(offset);
         if (botButton != null) {
             botButton.setTranslationX(offset);
@@ -6176,6 +6206,29 @@ public class ChatActivityEnterView extends FrameLayout implements
         updateRecordInterface(RECORD_STATE_CANCEL, true);
     }
 
+    public void inu_toggleVideoMode() {
+        setRecordVideoButtonVisible(!isInVideoMode(), true);
+    }
+
+    public void inu_startRecordingLocked(boolean video) {
+        createRecordCircle();
+        setRecordVideoButtonVisible(video, false);
+        // pre-set locked state so updateRecordInterface skips the slide-to-cancel intro
+        sendButtonVisible = true;
+        snapAnimationProgress = 1f;
+        slideToCancelProgress = 1f;
+        controlsScale = 1f;
+        lastRecordState = RECORD_STATE_PREPARING;
+        recordAudioVideoRunnable.run();
+        if (!recordingAudioVideo) {
+            // recording didn't start (e.g. missing permissions), reset state
+            sendButtonVisible = false;
+            return;
+        }
+        // the container must be visible for send button touch handling
+        audioVideoButtonContainer.setVisibility(VISIBLE);
+    }
+
     public void showContextProgress(boolean show) {
         if (progressDrawable == null) {
             return;
@@ -8095,14 +8148,14 @@ public class ChatActivityEnterView extends FrameLayout implements
             } else {
                 color = getThemedColor(Theme.key_chat_messagePanelSend);
             }
-            boolean captionNearAttach = messageEditText != null && (!TextUtils.isEmpty(messageEditText.getCaption()) || messageEditText.isNearRightCaption(dp(DEFAULT_HEIGHT))) || LocaleController.isRTL;
+            boolean captionNearAttach = VoiceRecorderHelper.isMovedToAttach() || messageEditText != null && (!TextUtils.isEmpty(messageEditText.getCaption()) || messageEditText.isNearRightCaption(dp(DEFAULT_HEIGHT))) || LocaleController.isRTL;
 
             if (color != sendButtonBackgroundColor) {
                 sendButtonBackgroundColor = color;
                 Theme.setSelectorDrawableColor(sendButton.getBackground(), Color.argb(24, Color.red(color), Color.green(color), Color.blue(color)), true);
             }
 
-            if (audioVideoButtonContainer.getVisibility() == VISIBLE || slowModeButton.getVisibility() == VISIBLE || showBotButton || showSendButton || animatorIsBlockedByStreaming.getValue()) {
+            if (audioVideoButtonContainer.getVisibility() == VISIBLE || VoiceRecorderHelper.isMovedToAttach() || slowModeButton.getVisibility() == VISIBLE || showBotButton || showSendButton || animatorIsBlockedByStreaming.getValue()) {
                 if (animated) {
                     if (runningAnimationType == 1 && caption == null || runningAnimationType == 3 && caption != null) {
                         return;
@@ -14672,7 +14725,7 @@ public class ChatActivityEnterView extends FrameLayout implements
     private void updateAttachLayoutParams() {
         updateAttachButtonTranslationX();
         if (attachLayout != null) {
-            attachLayout.setTranslationX(attachLayoutPaddingTranslationX + attachLayoutTranslationX);
+            attachLayout.setTranslationX(VoiceRecorderHelper.attachTranslationXOffset() + attachLayoutPaddingTranslationX + attachLayoutTranslationX);
             attachLayout.setAlpha(attachLayoutAlpha * attachLayoutPaddingAlpha);
             attachLayout.setVisibility(attachLayout.getAlpha() > 0 ? View.VISIBLE : View.GONE);
             if (attachButton != null && isStories) {
@@ -14689,8 +14742,8 @@ public class ChatActivityEnterView extends FrameLayout implements
     }
 
     private void updateAttachButtonTranslationX() {
-        if (attachButton == null) return;
-        attachButton.setTranslationX(attachLayoutPaddingTranslationX + attachLayoutTranslationX + (sendButton != null ? (
+        if (attachButton == null || VoiceRecorderHelper.isMovedToAttach()) return;
+        attachButton.setTranslationX(VoiceRecorderHelper.attachTranslationXOffset() + attachLayoutPaddingTranslationX + attachLayoutTranslationX + (sendButton != null ? (
             -Math.max(0, sendButton.width() - dp(DEFAULT_HEIGHT + 12)) * sendButton.getAlpha()
         ) : 0));
     }
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 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlert.java
@@ -1081,7 +1081,7 @@ public class ChatAttachAlert extends BottomSheet implements NotificationCenter.N
     private ChatActivityFadeView fadeView;
 
     private View bottomFadeView;
-    protected FrameLayout buttonsRecyclerViewWrapper;
+    public FrameLayout buttonsRecyclerViewWrapper;
     protected RecyclerListView buttonsRecyclerView;
 
     private LinearLayoutManager buttonsLayoutManager;
diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java
index 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/InstantCameraView.java
@@ -69,6 +69,7 @@ import androidx.core.graphics.ColorUtils;
 
 import com.google.android.exoplayer2.ExoPlayer;
 
+import desu.inugram.helpers.chat.VoiceRecorderHelper;
 import org.telegram.messenger.AndroidUtilities;
 import org.telegram.messenger.ApplicationLoader;
 import org.telegram.messenger.AutoDeleteMediaTask;
@@ -730,9 +731,7 @@ public class InstantCameraView extends FrameLayout implements NotificationCenter
         cameraReady = false;
         selectedCamera = null;
         if (!fromPaused) {
-            if (!useCamera2) {
-                isFrontface = true;
-            }
+            isFrontface = VoiceRecorderHelper.nextCameraFront;
             updateFlash();
             recordedTime = 0;
             progress = 0;
