Skip to content

Add archive action to chat list long-press and desktop context menus - #217

Merged
iebb merged 1 commit into
iebb:masterfrom
TiaraBasori:fix/chat-list-archive-action
Oct 16, 2026
Merged

iebb merged 1 commit into
iebb:masterfrom
TiaraBasori:fix/chat-list-archive-action

Conversation

@TiaraBasori

@TiaraBasori TiaraBasori commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Change

Main-list chat rows lacked an explicit Archive entry in the mobile long-press preview menu and the desktop right-click context menu.

  • Mobile long-press preview (_showChatPreview in lib/chats/chat_list_view.dart): adds a ChatListPreviewAction(label: AppStringKeys.chatListArchive, icon: HeroAppIcons.archiveBox, onSelected: () => _model.archive(chat, owner: owner)) row between Pin and Mute.
  • Desktop right-click context menu (DesktopChatContextMenu in lib/chats/chat_list_view.dart): adds a _DesktopChatContextMenuItem(key: ValueKey('desktop-chat-context-archive'), icon: HeroAppIcons.archiveBox, label: AppStringKeys.chatListArchive, onTap: () => _select(onArchive)) row after Mute and updates _menuHeight for the extra 38px row.
  • Account ownership across delayed menu dismissal (lib/chats/chat_list_preview.dart, lib/chats/chat_list_view_model.dart, lib/chats/chat_list_view.dart): pins the foreground ChatPreviewOwner (_TdChatPreviewAccounts.pinActiveOwner()) when opening the preview or desktop context menu. showChatListPreview re-checks owner.isCurrent after await route.completed (the reverse transition), and ChatListViewModel.archive(chat, {owner}) verifies !_disposed and owner.isCurrent before dispatching addChatToList (chatListArchive) through owner.query (bound to owner.clientId), so an account switch, session replacement, slot close, or shutdown during delayed dismissal suppresses the action instead of archiving on the replacement account.
  • Localization: adds chatListArchive across all 8 locales (lib/l10n/app_localizations.dart, translations/strings/<locale>/strings.xml, regenerated assets/l10n/<locale>.json).
  • Affected platforms: mobile/tablet (showChatListPreview) and desktop (DesktopChatContextMenu).

Telegram API Terms classification

Follow the contribution and agentic review rules. Select exactly one classification and explain it below.

This is an agentic source-code review classification. Every store version must remain compliant with applicable Telegram API Terms; the guarded-source exception does not apply to store distribution or review.

  • Compliant/unchanged: this change complies with applicable Telegram API Terms, preserves Telegram's basic functionality, and does not introduce behavior covered by section 1.4.
  • Section 1.4 exception: the entire feature is guarded by allowTelegramTosViolations (I_DONT_FUCKING_CARE_ABOUT_TOS), disabled in official builds, and available only in an explicitly enabled self-build.
  • Disallowed or unresolved: this PR must not be approved or merged until its classification and implementation are resolved.

Reason and affected Telegram behavior: Exposes an explicit user-triggered Archive action (addChatToList with chatListArchive) in the chat-list menus, matching the existing unarchive path (addChatToList with chatListMain). Does not modify read receipts, typing indicators, online status, self-destructing media, or message retention, and introduces no section 1.4 behavior.

Basic checks (every PR)

Check each item after verification. If a check is inapplicable, explain why in the evidence below before checking it.

  • I reviewed the diff for correctness, unintended behavior, secrets, and unrelated changes.
  • Formatting passed, or I recorded why it is inapplicable: dart format --output=none --set-exit-if-changed on the 6 changed .dart files (CI Dart SDK 3.12.2 / Flutter 3.44.2, Formatted 6 files (0 changed)).
  • Analysis passed, or I recorded why it is inapplicable: flutter analyze on the 6 changed .dart files (No issues found!).
  • Relevant tests passed, or I recorded why they are inapplicable; name the commands and test cases below. Quality CI runs flutter test --concurrency=4.
  • I checked affected build/platform paths and applicable localization/generated files; list the evidence below.
  • I completed the Terms classification above and verified that official builds cannot enable section 1.4 exceptions.

Commands, results, platform/build/UI evidence, and reasons for inapplicable checks:

  • ~/.cache/dart3122/bin/dart format --output=none --set-exit-if-changed lib/chats/chat_list_preview.dart lib/chats/chat_list_view.dart lib/chats/chat_list_view_model.dart lib/components/app_icons.dart lib/l10n/app_localizations.dart test/chat_list_preview_test.dart → Formatted 6 files (0 changed)
  • PATH=/tmp/flutter-3.44.2/bin:$PATH flutter analyze lib/chats/chat_list_preview.dart lib/chats/chat_list_view.dart lib/chats/chat_list_view_model.dart lib/components/app_icons.dart lib/l10n/app_localizations.dart test/chat_list_preview_test.dart → No issues found!
  • PATH=/tmp/flutter-3.44.2/bin:$PATH flutter test --no-pub -j 1 test/chat_list_preview_test.dart test/chat_list_view_model_lifecycle_test.dart test/l10n_completeness_test.dart → 61/61 passed:
    • test/chat_list_preview_test.dart (34 passed, including desktop context menu archive dispatches addChatToList/chatListArchive to the pinned owner, chat preview offers archive and dismisses before invoking, and preview archive is suppressed when account ownership changes during delayed dismissal)
    • test/chat_list_view_model_lifecycle_test.dart (7 passed)
    • test/l10n_completeness_test.dart (20 passed)
  • Failing-first verification: on pre-fix e8bb01d9, ChatListViewModel.archive took no owner and dispatched through TdClient.shared.query (resolving the current foreground client after route.completed), so switching accounts or replacing the slot's client during the 220ms reverse transition dispatched addChatToList(chat_id: 42, chatListArchive) to the replacement account instead of dropping it.
  • Localization & generated checks:
    • python3 tool/check_l10n_strings.py → No visible UI string literals outside lib/l10n.
    • python3 translations/tools/check.py → 8 locales x 3830 keys (11 counted): OK
    • python3 translations/tools/gen_assets.py --check → 9 locale assets are up to date
    • python3 tool/gen_registration_anchors.py --check → exit 0

Section 1.4 exception checks

Not applicable

Agentic reviewer confirmation

Agentic code reviewer only: record this confirmation in the PR review or check these boxes before approval.

  • I independently confirmed the Terms classification and inspected all required guards and evidence.
  • Applicable checks and Quality CI pass; no unresolved classification or unguarded section 1.4 behavior remains.

@iebb iebb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed e8bb01d against master 066c2d6 in an isolated credential-free snapshot; all 21 changed-file blobs (including regenerated locales) match. The new Archive entry uses owned icons and the existing non-destructive addChatToList/chatListArchive behavior. 59 focused preview/model/localization tests pass; scoped formatting/analyzer, 8 locales x 3827 keys, generated assets, visible strings, and registration anchors pass. Exact-head Quality CI is green.

Before approval/merge, complete .github/pull_request_template.md as required by AGENTS.md: select exactly one Telegram API Terms classification, explain the affected behavior, check the basic evidence items, and mark section 1.4 exception checks not applicable if classifying this ordinary explicit archive action as compliant/unchanged. The current Summary/Test plan omits that mandatory classification/checklist. The source review finds this consistent with ordinary explicit archive behavior; that does not replace the required contribution declaration.

Please also pin the production archive request (chat ID/list and account ownership across delayed menu dismissal), rather than only a stand-in callback, in focused coverage. No Telegram account or native operation was exercised. Direct Git fetching is currently unavailable, so no local commit, merge, or push was made. This is a legitimate improvement, not a rejection/closure.

- Long-pressing an unarchived chat in the main chat list now offers
  Archive in the preview action menu (between Pin and Mute), dispatching
  addChatToList -> chatListArchive.
- The desktop right-click context menu gets the same Archive item (after
  Mute); DesktopChatContextMenu._menuHeight updated for the extra row.
- Pin the foreground ChatPreviewOwner when opening the preview or
  desktop context menu; showChatListPreview re-checks owner.isCurrent
  after the delayed dismissal transition, and ChatListViewModel.archive
  verifies owner.isCurrent and dispatches through owner.query so an
  account switch or client replacement mid-dismissal drops the request
  instead of mutating the replacement account.
- New l10n key chatListArchive across all 8 locales.
@TiaraBasori
TiaraBasori force-pushed the fix/chat-list-archive-action branch from e8bb01d to 079e7d8 Compare October 16, 2026 11:57
@TiaraBasori

Copy link
Copy Markdown
Contributor Author

Updated and rebased onto current master (f311e347) in 079e7d84:

  1. Completed .github/pull_request_template.md in the PR description with the Compliant/unchanged Telegram API Terms classification, explanation, basic-check commands/outputs, and Not applicable for Section 1.4 exception checks.
  2. Production archive request & account ownership across delayed menu dismissal:
    • showChatListPreview now pins the active ChatPreviewOwner at open and re-checks owner.isCurrent after await route.completed before invoking selected.onSelected().
    • _showChatPreview and _showDesktopChatMenu pin the active ChatPreviewOwner and pass it to ChatListViewModel.archive(chat, owner: owner), which verifies !_disposed and owner.isCurrent and dispatches {@type: 'addChatToList', chat_id: chat.id, chat_list: {@type: 'chatListArchive'}} through owner.query (bound to owner.clientId).
    • Added focused coverage in test/chat_list_preview_test.dart:
      • chat preview offers archive and dismisses before invoking (verifies no request is sent while the dismissal animation is in flight, then pins the exact addChatToList / chatListArchive payload and client owner 10 after settle)
      • preview archive is suppressed when account ownership changes during delayed dismissal (switches active slot and replaces same-slot client mid-dismissal at 60ms; asserts zero requests sent to either account)
      • desktop context menu archive dispatches addChatToList/chatListArchive to the pinned owner (pins payload on client 10 and verifies that switching to slot 1 suppresses subsequent invocations)

@iebb iebb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 079e7d8. The required declaration and production request/account-ownership tests requested earlier are now present. All 61 supplied/adjacent menu/model/localization tests pass, including dispatch through the pinned client and suppression during delayed-dismissal account/session replacement.

One additional failing-first boundary exposed a null-owner fallback: archive(chat, owner:null) dispatched addChatToList/chatListArchive through the later active account. The intended maintainer merge repairs this narrowly: owner is a required nullable argument, a missing or expired owner fails closed, and the request uses only owner.query (never a foreground-client fallback). A new archive_owner_boundary_test.dart drives the actual shared proxy transport and proves no request escapes. The repaired focused set passes 62 tests. Repair files are only lib/chats/chat_list_view_model.dart and that regression test; other reviewed PR files are unchanged. This confirmation covers the repaired intended integration, not approval to merge the unmodified head.

Independently reviewed the actual production diff and affected entry points. The completed contribution template is present; classification is compliant/unchanged, with no Section 1.4 feature or required exception guard. No authentication, protocol/native, storage-schema, release/deployment, or official-build flag path changes. Credential-free snapshots use secrets_example.dart only. The combined intended master tree 6202d9cf8812ed9ca91a39422039a4cfbcee0102 passes all 3,449 unit/widget tests (one existing skip), formatting of 999 files with zero changes, full analysis, 8 locales x 3830 keys / 9 generated locale assets, visible-string and registration checks, and explicit false/true/invalid build-flag tests. Current exact-head Quality is green. Platform evidence here is shared Flutter layout/navigation/selection testing, not native-device QA; no Telegram, real account, deployment, or store action was used.

@iebb
iebb merged commit 7cdd0b2 into iebb:master Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants