Skip to content

feat(chat): force gallery refresh on attach open and add quick-send popup#95

Merged
NextAlone merged 7 commits into
mainfrom
claude/fix-photo-loading-quick-send-TVpN2
Apr 19, 2026
Merged

feat(chat): force gallery refresh on attach open and add quick-send popup#95
NextAlone merged 7 commits into
mainfrom
claude/fix-photo-loading-quick-send-TVpN2

Conversation

@NextAlone

Copy link
Copy Markdown
Owner
  • force MediaStore reload when opening the attach menu so newly taken
    photos and screenshots appear without waiting for the observer's 2s
    debounce
  • add a bottom-right floating popup in ChatActivity that surfaces the
    latest image (added while the chat was away) and quick-sends it on
    tap; detection runs only on onResume / first entry
  • new setting under Chat settings: "Quick send popup for new photos"

…opup

- force MediaStore reload when opening the attach menu so newly taken
  photos and screenshots appear without waiting for the observer's 2s
  debounce
- add a bottom-right floating popup in ChatActivity that surfaces the
  latest image (added while the chat was away) and quick-sends it on
  tap; detection runs only on onResume / first entry
- new setting under Chat settings: "Quick send popup for new photos"
Copilot AI review requested due to automatic review settings April 19, 2026 07:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a “quick send latest photo” affordance in chats and makes the attach gallery refresh immediately so newly captured media appears without waiting for the observer debounce.

Changes:

  • Always triggers a MediaStore albums reload when opening the attach menu.
  • Introduces QuickSendMediaPopup and integrates it into ChatActivity (query latest image on resume and quick-send on tap).
  • Adds a new chat setting + localized strings to enable/disable the popup.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
TMessagesProj/src/main/res/values/strings_nullgram.xml Adds new UI strings for the quick-send popup setting/prompt.
TMessagesProj/src/main/res/values-zh/strings_nullgram.xml Chinese translations for the new quick-send popup strings.
TMessagesProj/src/main/res/values-zh-rTW/strings_nullgram.xml Traditional Chinese translations for the new quick-send popup strings.
TMessagesProj/src/main/java/xyz/nextalone/nnngram/utils/Defines.kt Adds a new boolean config key for enabling the popup.
TMessagesProj/src/main/java/xyz/nextalone/nnngram/ui/QuickSendMediaPopup.java New UI component + MediaStore query/thumb decode logic.
TMessagesProj/src/main/java/xyz/nextalone/nnngram/activity/ChatSettingActivity.java Adds a settings row to toggle the popup.
TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachAlertPhotoLayout.java Forces gallery refresh on attach open.
TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java Wires popup into chat lifecycle and sending flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +302 to +303
<string name="quickSendMediaPopupTitle">发送新照片?</string>
<string name="quickSendMediaPopupSending">发送中…</string>

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

The newly added quickSendMediaPopupTitle / quickSendMediaPopupSending strings don’t appear to be referenced anywhere in the codebase. If they aren’t going to be used in the UI, consider removing them (or using them) to avoid carrying unused translations.

Suggested change
<string name="quickSendMediaPopupTitle">发送新照片?</string>
<string name="quickSendMediaPopupSending">发送中…</string>

Copilot uses AI. Check for mistakes.
Comment on lines +299 to +300
<string name="quickSendMediaPopupTitle">傳送新照片?</string>
<string name="quickSendMediaPopupSending">傳送中…</string>

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

The newly added quickSendMediaPopupTitle / quickSendMediaPopupSending strings don’t appear to be referenced anywhere in the codebase. If they aren’t going to be used in the UI, consider removing them (or using them) to avoid carrying unused translations.

Suggested change
<string name="quickSendMediaPopupTitle">傳送新照片?</string>
<string name="quickSendMediaPopupSending">傳送中…</string>

Copilot uses AI. Check for mistakes.
Comment on lines +233 to +234
bitmap = android.provider.MediaStore.Images.Media.getBitmap(
ApplicationLoader.applicationContext.getContentResolver(), e.uri);

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

decodeThumb() falls back to MediaStore.Images.Media.getBitmap() for URI sources, which decodes the full-size image (and is deprecated). This can cause unnecessary memory usage/OOM for large photos; consider decoding via ImageDecoder (API 28+) or sampling from a ContentResolver InputStream to the target size, similar to the file-path branch.

Suggested change
bitmap = android.provider.MediaStore.Images.Media.getBitmap(
ApplicationLoader.applicationContext.getContentResolver(), e.uri);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
try (java.io.InputStream boundsStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(e.uri)) {
if (boundsStream != null) {
BitmapFactory.decodeStream(boundsStream, null, opts);
}
}
int w = opts.outWidth;
int h = opts.outHeight;
int sample = 1;
while (w / sample > target * 2 && h / sample > target * 2) {
sample *= 2;
}
BitmapFactory.Options decodeOpts = new BitmapFactory.Options();
decodeOpts.inSampleSize = sample;
try (java.io.InputStream decodeStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(e.uri)) {
if (decodeStream != null) {
bitmap = BitmapFactory.decodeStream(decodeStream, null, decodeOpts);
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +291 to +303
// DATA column may be null on Android 10+ in some cases; fall back to EXIF via URI later.
if (e.orientation == 0 && e.path != null) {
try {
ExifInterface exif = new ExifInterface(e.path);
int o = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (o) {
case ExifInterface.ORIENTATION_ROTATE_90: e.orientation = 90; break;
case ExifInterface.ORIENTATION_ROTATE_180: e.orientation = 180; break;
case ExifInterface.ORIENTATION_ROTATE_270: e.orientation = 270; break;
}
} catch (Throwable ignored) {
}
}

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

queryLatestImage() only derives EXIF orientation when a filesystem path is available. On Android 10+ the DATA column can be null, which means orientation will remain 0 and the popup thumbnail may display rotated incorrectly. Consider reading EXIF orientation from the URI via ContentResolver (ExifInterface(InputStream)) when path is null.

Copilot uses AI. Check for mistakes.
Comment on lines +29804 to +29811
final long sinceSec;
if (quickSendPauseTimeSec > 0) {
// Only show photos added while we were away from this chat.
sinceSec = quickSendPauseTimeSec;
} else {
// First time entering: look back 3 minutes for a freshly taken shot.
sinceSec = System.currentTimeMillis() / 1000L - 180L;
}

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

The MediaStore query uses DATE_ADDED + " > ?" with seconds precision. In ChatActivity, sinceSec is set to the pause timestamp in seconds, so photos added within the same second as onPause() can be missed. Consider using ">= ?" or subtracting 1s from sinceSec when querying to avoid off-by-one-second misses.

Copilot uses AI. Check for mistakes.
Comment on lines +511 to +513
private QuickSendMediaPopup quickSendMediaPopup;
private long quickSendPauseTimeSec;
private final java.util.HashSet<Long> quickSendDismissedIds = new java.util.HashSet<>();

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

quickSendDismissedIds is an unbounded HashSet that accumulates every sent/dismissed MediaStore ID for the lifetime of the ChatActivity. Over long sessions this can grow without limit; consider capping it (e.g., LRU of last N IDs) or clearing it when leaving the chat / after a successful send.

Copilot uses AI. Check for mistakes.
Comment on lines +2562 to +2567
public void loadGalleryPhotos() {
MediaController.AlbumEntry albumEntry;
if (shouldLoadAllMedia()) {
albumEntry = MediaController.allMediaAlbumEntry;
} else {
albumEntry = MediaController.allPhotosAlbumEntry;
}
if (albumEntry == null) {
MediaController.loadGalleryPhotosAlbums(0);
}
// Always request a MediaStore refresh so newly added photos/screenshots
// appear without waiting for the ContentObserver's 2s debounce. The load
// runs on a background thread and updates the UI via NotificationCenter
// (albumsDidLoad) while the cached album (if any) keeps rendering.
MediaController.loadGalleryPhotosAlbums(0);

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

loadGalleryPhotos() now always calls MediaController.loadGalleryPhotosAlbums(0), which spawns a new Thread and performs a full MediaStore scan each time the attach UI opens. This can lead to redundant concurrent reloads and UI churn if the attach menu is opened repeatedly; consider throttling (timestamp/debounce) or guarding against parallel loads in MediaController before starting another scan.

Copilot uses AI. Check for mistakes.
Comment on lines +306 to +307
<string name="quickSendMediaPopupTitle">Send new photo?</string>
<string name="quickSendMediaPopupSending">Sending…</string>

Copilot AI Apr 19, 2026

Copy link

Choose a reason for hiding this comment

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

The newly added strings quickSendMediaPopupTitle and quickSendMediaPopupSending don’t appear to be referenced anywhere in the codebase (no usages found). If they’re not planned for immediate use, consider removing them to avoid dead resources, or wire them into the popup UI so the prompt/sending state is actually shown.

Suggested change
<string name="quickSendMediaPopupTitle">Send new photo?</string>
<string name="quickSendMediaPopupSending">Sending…</string>

Copilot uses AI. Check for mistakes.
claude added 6 commits April 19, 2026 08:05
- show an Alert confirmation before the quick-send popup actually sends,
  so an accidental tap no longer fires the message
- MediaController.loadGalleryPhotosAlbums now takes an urgent flag:
  attach-menu opens get NORM_PRIORITY (was MIN_PRIORITY) and parallel
  scans are coalesced via an atomic flag + queued rerun
- add MediaController.quickRefreshLatestPhotos: a lightweight MediaStore
  query for the top N rows that prepends just-taken photos into the
  cached All Media / All Photos albums and broadcasts albumsDidLoad
  right away, so the attach grid surfaces new shots in ~100ms while the
  full rescan keeps running in the background
Closing the popup with x now records the image in the per-instance
dismissed set and nudges the detection watermark past its DATE_ADDED,
so the same photo won't resurface on the next onResume.
uploadCI.py wraps $COMMIT_MESSAGE in a triple-backtick fence and sends
it with parse_mode=Markdown. When the commit body carries single
backticks (e.g. identifier spans like the recent retention / filter
commits) the inner ` clashes with the outer ```, Telegram returns
"can't parse entities" and the upload step fails. Sanitize the env var
in the workflow so the uploader still formats normally while the body
stays legal.
…ssals

- tapping the quick-send popup now opens the standard PhotoViewer
  preview/editor with Send, so users can review (and caption/crop) the
  photo before it goes out, matching the attach-menu selection flow
- persist the last dismissed image id in ConfigManager under
  quickSendMediaLastDismissedId; any MediaStore photo with a smaller or
  equal id is never resurfaced, so closing the popup with x stays
  dismissed across fragment re-entries and process restarts
Move the popup from bottomMargin=110 / rightMargin=6 (stacked above
sideControlsButtonsLayout) to bottomMargin=6 / rightMargin=64, so it
sits just above the input bar and to the left of the scroll-to-bottom
button (clear of the 57dp-wide side controls column). Feels like a
proper bottom-right affordance instead of floating mid-chat.
…ight

- persist the dismissal watermark the moment the popup surfaces a photo,
  so send / cancel-from-preview / 10s timeout / leaving the chat all
  count as "already seen" and the same image can never pop again
- move popup to rightMargin=6 / bottomMargin=60 so it sits right-aligned
  with the scroll-to-bottom button and just above it, instead of floating
  further left with oversized right margin
@NextAlone NextAlone merged commit ce16eef into main Apr 19, 2026
1 check passed
seyrenus added a commit to seyrenus/Nnngram that referenced this pull request Apr 29, 2026
* feat(chat): force gallery refresh and add quick-send popup for new photos (NextAlone#95)

Clicking the attachment button now forces a MediaStore refresh so
newly-added photos and screenshots appear without waiting for the
ContentObserver's 2s debounce. Attach-menu opens run the scan at
NORM_PRIORITY (was MIN), parallel scans coalesce via an atomic
in-flight flag, and a new quickRefreshLatestPhotos fast-path
prepends the top N MediaStore rows into the cached album so new
shots surface in the grid in ~100ms while the full rescan finishes.

Adds a bottom-right floating popup in ChatActivity that surfaces
the latest image taken while away and, on tap, opens the standard
PhotoViewer preview/editor so the user can review, caption or
cancel before sending. Detection runs only on onResume / first
entry; gated on chatMode, preview/bubble/report/container state,
secret chat, ChatObject.canSendPhoto and the images permission.
The popup auto-dismisses after 10s; a persisted watermark
(quickSendMediaLastDismissedId) is written the moment a photo is
shown so send / preview-cancel / timeout / leaving the chat / cold
restart all count as already seen and the same image never pops
again. Ships with a toggle in the Nnngram Chat settings
(quickSendMediaPopup, default on) and en / zh-CN / zh-TW strings.

CI: strip backticks from COMMIT_MESSAGE before uploadCI.py so the
triple-backtick fence in the Telegram template stops colliding with
inline-code spans in the commit body and the release notification
stops failing with "can't parse entities".

* ci: truncate commit message before telegram upload (NextAlone#96)

sendDocument caption limit is 1024 chars. After backtick-stripping,
long commit bodies still bust the limit and uploadCI.py fails with
400 Bad Request. Do both the strip and an 800-char cap in one Python
step so the release notification survives verbose commits.

* feat(chat-menu): add compact icon bar w/ 3-state toggle

Long context menu now supports per-option HIDE / TEXT / ICON
modes via segmented control in chat settings. Icon mode renders
options as a horizontal GridLayout (≤4 cols) at popup bottom.

- store compact + hidden sets as CSV in SharedPreferences
- migrate stale `compactBarPosition` int from earlier draft
- Translate stays HIDE/TEXT only — compact would lose swipeback
  + lang detection wiring
- Delete works in icon mode (TTL subtext lost; confirm dialog
  still fires)
- order in dialog mirrors fillMessageMenu sequence

---------

Co-authored-by: Next Alone <12210746+NextAlone@users.noreply.github.com>
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.

3 participants