From 69695cd718afc7397a184f70082424c5807f0104 Mon Sep 17 00:00:00 2001 From: ROCKET Date: Wed, 25 Feb 2026 13:03:11 -0600 Subject: [PATCH] Allow owner-granted no-forward bypass for admins --- .../messenger/MessagesController.java | 22 ++++++++++---- .../java/org/telegram/ui/ChatActivity.java | 16 ++++++++-- .../org/telegram/ui/ChatEditTypeActivity.java | 22 -------------- .../telegram/ui/ChatRightsEditActivity.java | 29 +++++++++++++++++-- 4 files changed, 57 insertions(+), 32 deletions(-) diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index a4658cd33cf..188aea4715d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -6587,20 +6587,32 @@ private boolean shouldBypassNoForwardsForCurrentUser(TLRPC.Chat chat) { if (chat.creator) { return true; } - return ChatObject.hasAdminRights(chat) && isNoForwardsAdminsBypassEnabled(chat.id); + return ChatObject.hasAdminRights(chat) && isNoForwardsAdminBypassEnabled(chat.id, getUserConfig().getClientUserId()); } - private String getNoForwardsAdminsBypassKey(long chatId) { - return "noforwards_admins_bypass_" + chatId; + private String getNoForwardsAdminsBypassKey(long chatId, long userId) { + return "noforwards_admins_bypass_" + chatId + "_" + userId; + } + + public boolean canBypassNoForwards(long chatId) { + return shouldBypassNoForwardsForCurrentUser(getChat(chatId)); } public boolean isNoForwardsAdminsBypassEnabled(long chatId) { - return getMainSettings().getBoolean(getNoForwardsAdminsBypassKey(chatId), false); + return isNoForwardsAdminBypassEnabled(chatId, getUserConfig().getClientUserId()); } public void setNoForwardsAdminsBypassEnabled(long chatId, boolean enabled) { + setNoForwardsAdminBypassEnabled(chatId, getUserConfig().getClientUserId(), enabled); + } + + public boolean isNoForwardsAdminBypassEnabled(long chatId, long userId) { + return getMainSettings().getBoolean(getNoForwardsAdminsBypassKey(chatId, userId), false); + } + + public void setNoForwardsAdminBypassEnabled(long chatId, long userId, boolean enabled) { SharedPreferences.Editor editor = getMainSettings().edit(); - editor.putBoolean(getNoForwardsAdminsBypassKey(chatId), enabled); + editor.putBoolean(getNoForwardsAdminsBypassKey(chatId, userId), enabled); editor.apply(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index a5b54f252f3..20c10f30926 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -11800,12 +11800,20 @@ private void destroyTextureView() { contentView.removeView(videoPlayerContainer); } + private boolean canBypassMessageNoForwards(MessageObject messageObject) { + if (messageObject == null || messageObject.messageOwner == null || !messageObject.messageOwner.noforwards) { + return false; + } + long sourceDialogId = messageObject.getDialogId(); + return sourceDialogId < 0 && getMessagesController().canBypassNoForwards(-sourceDialogId); + } + private boolean hasSelectedNoforwardsMessage() { try { for (int i = 0; i < selectedMessagesIds.length; ++i) { for (int j = 0; j < selectedMessagesIds[i].size(); ++j) { MessageObject msg = selectedMessagesIds[i].valueAt(j); - if (msg != null && msg.messageOwner != null && msg.messageOwner.noforwards) { + if (msg != null && msg.messageOwner != null && msg.messageOwner.noforwards && !canBypassMessageNoForwards(msg)) { return true; } } @@ -18600,7 +18608,8 @@ private void addToSelectedMessages(MessageObject messageObject, boolean outside, cantDeleteMessagesCount--; } boolean noforwards = getMessagesController().isChatNoForwards(currentChat); - if (chatMode == MODE_SCHEDULED || !messageObject.canForwardMessage() || noforwards) { + boolean canForwardMessage = messageObject.canForwardMessage() || canBypassMessageNoForwards(messageObject); + if (chatMode == MODE_SCHEDULED || !canForwardMessage || noforwards) { cantForwardMessagesCount--; } else { canForwardMessagesCount--; @@ -18637,7 +18646,8 @@ private void addToSelectedMessages(MessageObject messageObject, boolean outside, cantDeleteMessagesCount++; } boolean noforwards = getMessagesController().isChatNoForwards(currentChat); - if (chatMode == MODE_SCHEDULED || !messageObject.canForwardMessage() || noforwards) { + boolean canForwardMessage = messageObject.canForwardMessage() || canBypassMessageNoForwards(messageObject); + if (chatMode == MODE_SCHEDULED || !canForwardMessage || noforwards) { cantForwardMessagesCount++; } else { canForwardMessagesCount++; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java index 52dc495b296..f1f9541170b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatEditTypeActivity.java @@ -125,7 +125,6 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe private LinearLayout saveContainer; private HeaderCell saveHeaderCell; private TextCheckCell saveRestrictCell; - private TextCheckCell saveRestrictAdminBypassCell; private TextInfoPrivacyCell saveRestrictInfoCell; private JoinToSendSettingsView joinContainer; @@ -137,7 +136,6 @@ public class ChatEditTypeActivity extends BaseFragment implements NotificationCe private long chatId; private boolean isChannel; private boolean isSaveRestricted; - private boolean isAdminsSavingRestrictionBypassed; private boolean canCreatePublic = true; private boolean loadingAdminedChannels; @@ -185,7 +183,6 @@ public boolean onFragmentCreate() { isPrivate = !isForcePublic && !ChatObject.isPublic(currentChat); isChannel = ChatObject.isChannel(currentChat) && !currentChat.megagroup; isSaveRestricted = currentChat.noforwards; - isAdminsSavingRestrictionBypassed = getMessagesController().isNoForwardsAdminsBypassEnabled(chatId); if (isForcePublic && !ChatObject.isPublic(currentChat) || isPrivate && currentChat.creator) { TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); req.username = "1"; @@ -604,21 +601,9 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto saveRestrictCell.setOnClickListener(v -> { isSaveRestricted = !isSaveRestricted; ((TextCheckCell) v).setChecked(isSaveRestricted); - if (saveRestrictAdminBypassCell != null) { - saveRestrictAdminBypassCell.setVisibility(currentChat.creator && isSaveRestricted ? View.VISIBLE : View.GONE); - } }); saveContainer.addView(saveRestrictCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - saveRestrictAdminBypassCell = new TextCheckCell(context); - saveRestrictAdminBypassCell.setTextAndCheck(LocaleController.getString(R.string.OverrideRestriction), isAdminsSavingRestrictionBypassed, false); - saveRestrictAdminBypassCell.setOnClickListener(v -> { - isAdminsSavingRestrictionBypassed = !isAdminsSavingRestrictionBypassed; - ((TextCheckCell) v).setChecked(isAdminsSavingRestrictionBypassed); - }); - saveRestrictAdminBypassCell.setVisibility(currentChat.creator && isSaveRestricted ? View.VISIBLE : View.GONE); - saveContainer.addView(saveRestrictAdminBypassCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); - saveRestrictInfoCell = new TextInfoPrivacyCell(context, 12, resourceProvider); if (isChannel && !ChatObject.isMegagroup(currentChat)) { saveRestrictInfoCell.setText(LocaleController.getString(R.string.RestrictSavingContentInfoChannel)); @@ -1140,12 +1125,6 @@ protected void dispatchDraw(Canvas canvas) { } private boolean trySetRestrict() { - if (!isSaveRestricted) { - isAdminsSavingRestrictionBypassed = false; - } - if (currentChat.creator) { - getMessagesController().setNoForwardsAdminsBypassEnabled(chatId, isAdminsSavingRestrictionBypassed); - } if (currentChat.noforwards != isSaveRestricted) { if (!ChatObject.isChannel(currentChat)) { updateDoneProgress(true); @@ -1153,7 +1132,6 @@ private boolean trySetRestrict() { if (param != 0) { chatId = param; currentChat = getMessagesController().getChat(param); - getMessagesController().setNoForwardsAdminsBypassEnabled(chatId, isAdminsSavingRestrictionBypassed); getMessagesController().toggleChatNoForwards(chatId, currentChat.noforwards = isSaveRestricted); processDone(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java index 3aa3c1d8487..2478fb82e3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatRightsEditActivity.java @@ -117,6 +117,8 @@ public class ChatRightsEditActivity extends BaseFragment implements Notification private String currentBannedRights = ""; private String currentRank; private String initialRank; + private boolean savingRestrictionBypass; + private boolean initialSavingRestrictionBypass; private int rowCount; private int manageRow; @@ -133,6 +135,7 @@ public class ChatRightsEditActivity extends BaseFragment implements Notification private int addUsersRow; private int pinMessagesRow; private int manageTopicsRow; + private int savingRestrictionBypassRow; private int rightsShadowRow; private int removeAdminRow; private int removeAdminShadowRow; @@ -213,6 +216,9 @@ public ChatRightsEditActivity(long userId, long channelId, TLRPC.TL_chatAdminRig if (myAdminRights == null) { myAdminRights = emptyAdminRights(currentType != TYPE_ADD_BOT || (currentChat != null && currentChat.creator)); } + if (currentChat != null && currentChat.noforwards && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT)) { + savingRestrictionBypass = initialSavingRestrictionBypass = MessagesController.getInstance(currentAccount).isNoForwardsAdminBypassEnabled(chatId, userId); + } if (type == TYPE_ADMIN || type == TYPE_ADD_BOT) { if (type == TYPE_ADD_BOT) { TLRPC.UserFull userFull = getMessagesController().getUserFull(userId); @@ -902,6 +908,8 @@ public void onScrollStateChanged(RecyclerView recyclerView, int newState) { } else { value = bannedRights.manage_topics = !bannedRights.manage_topics; } + } else if (position == savingRestrictionBypassRow) { + value = savingRestrictionBypass = !savingRestrictionBypass; } else if (position == addUsersRow) { if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { value = adminRights.invite_users = !adminRights.invite_users; @@ -1200,6 +1208,7 @@ private void updateRows(boolean update) { untilDateRow = -1; addBotButtonRow = -1; manageTopicsRow = -1; + savingRestrictionBypassRow = -1; rowCount = 3; permissionsStartRow = rowCount; @@ -1246,6 +1255,9 @@ private void updateRows(boolean update) { if (isForum) { manageTopicsRow = rowCount++; } + if (currentChat != null && currentChat.noforwards && currentChat.creator) { + savingRestrictionBypassRow = rowCount++; + } } } else if (currentType == TYPE_BANNED) { sendMessagesRow = rowCount++; @@ -1367,6 +1379,11 @@ private void onDonePressed() { adminRights.other = false; } } + if (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT) { + if (initialSavingRestrictionBypass != savingRestrictionBypass && currentChat != null && currentChat.noforwards && currentChat.creator) { + MessagesController.getInstance(currentAccount).setNoForwardsAdminBypassEnabled(chatId, currentUser.id, savingRestrictionBypass); + } + } boolean finishFragment = true; if (currentType == TYPE_ADMIN) { finishFragment = delegate == null; @@ -1617,6 +1634,7 @@ public long getItemId(int position) { if (position == channelEditStoriesRow) return 42; if (position == channelDeleteStoriesRow) return 43; if (position == manageDirectRow) return 44; + if (position == savingRestrictionBypassRow) return 45; return 0; } else { return super.getItemId(position); @@ -1626,7 +1644,7 @@ public long getItemId(int position) { @Override public boolean isEnabled(RecyclerView.ViewHolder holder) { int type = holder.getItemViewType(); - if (currentChat.creator && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin) && type == VIEW_TYPE_SWITCH_CELL && holder.getAdapterPosition() == anonymousRow) { + if (currentChat.creator && (currentType == TYPE_ADMIN || currentType == TYPE_ADD_BOT && asAdmin) && type == VIEW_TYPE_SWITCH_CELL && (holder.getAdapterPosition() == anonymousRow || holder.getAdapterPosition() == savingRestrictionBypassRow)) { return true; } if (!canEdit) { @@ -1664,6 +1682,8 @@ public boolean isEnabled(RecyclerView.ViewHolder holder) { return myAdminRights.pin_messages && (defaultBannedRights == null || defaultBannedRights.pin_messages); } else if (position == manageTopicsRow) { return myAdminRights.manage_topics; + } else if (position == savingRestrictionBypassRow) { + return currentChat != null && currentChat.creator; } else if (position == channelPostStoriesRow) { return myAdminRights.post_stories; } else if (position == channelEditStoriesRow) { @@ -1993,6 +2013,11 @@ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { checkCell.setTextAndCheck(LocaleController.getString(R.string.ManageTopicsPermission), asAdminValue && adminRights.manage_topics, false); checkCell.setIcon(myAdminRights.manage_topics || isCreator ? 0 : R.drawable.permission_locked); } + } else if (position == savingRestrictionBypassRow) { + checkCell.setTextAndCheck(LocaleController.getString(R.string.OverrideRestriction), savingRestrictionBypass, false); + if (currentType == TYPE_ADD_BOT) { + checkCell.setIcon(currentChat != null && currentChat.creator ? 0 : R.drawable.permission_locked); + } } else if (position == addUsersRow) { if (currentType == TYPE_ADMIN) { if (ChatObject.isActionBannedByDefault(currentChat, ChatObject.ACTION_INVITE)) { @@ -2099,7 +2124,7 @@ public int getItemViewType(int position) { return VIEW_TYPE_HEADER_CELL; } else if (position == changeInfoRow || position == postMessagesRow || position == manageDirectRow || position == editMesagesRow || position == deleteMessagesRow || position == addAdminsRow || position == banUsersRow || position == addUsersRow || position == pinMessagesRow || - position == sendMessagesRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow + position == sendMessagesRow || position == anonymousRow || position == startVoiceChatRow || position == manageRow || position == manageTopicsRow || position == savingRestrictionBypassRow ) { return VIEW_TYPE_SWITCH_CELL; } else if (position == cantEditInfoRow || position == rankInfoRow) {