Skip to content

[Feat, Enhancement] Improve in-chat scroll position | "New messages" separator #910

@dev-adamant-im

Description

@dev-adamant-im

Summary

Implement consistent behavior for in-chat scroll position, the Scroll to bottom button, and the New messages separator across all entry points

Motivation

Goal: predictable UX for reading and catching up on messages.

Users expect a chat app to restore their reading position accurately, show where new messages start, and provide a clear way to jump to either the newest or the first unread message.
Current behavior may be inconsistent, especially when switching between chats or receiving new messages while inside a chat.

Detailed description

Follow Specification: In-chat scroll position & New messages separator https://github.com/orgs/Adamant-im/discussions/24

Acceptance Criteria

  • Scroll state is saved/restored per chat consistently
  • “New messages” separator appears only in correct cases
  • Scroll to bottom button behaves as described
  • Edge cases covered (short chats, multiple notifications, entering from other screens)

QA Test Cases Checklist

Environment

  • Platforms: iOS, macOS
  • States: Logged in, multiple chats with varied history
  • Test data: Chats with 0/short/long histories; unread counts; images/files/long text
  • Network: Stable, Slow 3G, Offline/Airplane, VPN on/off
  • Orientation: Portrait & Landscape

A. Scroll State Saving

Precondition: User scrolls within a chat.

  • A1. At the very bottom → Do not save position (button hidden)
  • A2. Few pixels from bottom (button still hidden) → Do not save
  • A3. Not at bottom (button visible) → Save position
  • A4. Short chat (< screen height) → Always considered bottom → Do not save

Persistence

  • A5. Navigate away (to Chat list) and back → Position restored
  • A6. App background → foreground → Position preserved
  • A7. App restart → Position preserved per chat
  • A8. Switch to another chat → Return → Position restored

B. “Scroll to bottom” Button Visibility & Action

  • B1. Show when last single-line message is ~¾ hidden
  • B2. No new messages + above separator → Button scrolls to very bottom
  • B3. New messages present → Button scrolls to “New messages” separator
  • B4. Already below separator (separator visible or below) → Button scrolls to very bottom
  • B5. Button counter increments with each incoming message while not at bottom
  • B6. Counter resets after button tap or manual scroll past separator

C. “New messages” Separator Behavior

  • C1. Separator appears only when there are unread messages above current bottom
  • C2. Separator position: when scrolled via button, show separator with ~3 lines above
  • C3. No vibration/sound/highlight when jumping to separator
  • C4. Do not show separator before the very first message (e.g., first ever 10 msgs in new chat)

D. Events Matrix (Restore Logic)

1) Inside chat, message arrives

  • D1.1 No stored position → Auto-scroll to bottom for incoming & outgoing; no separator
  • D1.2 Stored position:
    • Incoming → Do not scroll; show button with counter; show separator
    • Outgoing → Scroll to bottom

2) Enter chat with new messages (from Chat list / other screens)

  • D2.1 No stored position → Jump to separator
  • D2.2 Stored position → Do not scroll; show button + counter; show separator

3) Enter from notification (in-app / push)

  • D3.1 No stored position → Jump to separator (even if multiple messages)
  • D3.2 Stored position → Same as above (do not jump to latest individual message)

E. Navigation Sources

  • E1. From Chat list (tap a chat with unread) → Correct target (separator or preserve)
  • E2. From “Go to chat” (e.g., Transaction list → Transaction details → Go to chat) → Same rules apply
  • E3. From search results → Same rules apply
  • E4. Deep link to chat → Same rules apply

F. Scrolling & Pagination

  • F1. Manual scroll upwards triggers history pagination without shifting saved position
  • F2. After history loads, separator location stays correct
  • F3. Very long messages / media do not break separator positioning
  • F4. Mixed content (images, files, replies) maintains correct “¾ hidden” detection

I. Performance & Stability

  • I1. Scroll/jump animations are smooth (<16ms frame budget on modern devices)
  • I2. No layout thrashing (avoid forced sync measures on scroll)
  • I3. Memory stable when jumping repeatedly between chats
  • I4. No double-invocation of scroll on event storms (debounced as needed)

J. Accessibility

  • J1. Button is keyboard/focus accessible; has ARIA label (e.g., “Scroll to new messages”)
  • J2. Separator is screen-reader discoverable (role/label: “New messages”)
  • J3. Contrast & touch target size meet WCAG AA

K. Visual / UX Validation

  • K1. Separator spacing: ~3 lines above on jump
  • K2. Button placement does not overlap FAB/Composer
  • K3. RTL locales render positions and offsets correctly
  • K4. Dark/Light themes: separator & button styling legible

L. Offline / Network Flaps

  • L1. Go offline while in chat → No crash; saved position logic unaffected
  • L2. Come back online → Separator & button reflect new arrivals without forced bottom scroll
  • L3. VPN / proxy switching does not duplicate separators or counters

Metadata

Metadata

Assignees

Labels

Composite taskLarge or complex task that consists of multiple subtaskSwiftiOS-specific code and features in SwiftUX/UIUser interface and experience improvementsenhancementNew feature or request

Projects

Status

Done (In develop)

Relationships

None yet

Development

No branches or pull requests

Issue actions