Skip to content

feat(mobile): day dividers, video upload, emoji picker & UX polish#396

Merged
wesbillman merged 10 commits intomainfrom
mobile-date-dividers
Apr 24, 2026
Merged

feat(mobile): day dividers, video upload, emoji picker & UX polish#396
wesbillman merged 10 commits intomainfrom
mobile-date-dividers

Conversation

@wesbillman
Copy link
Copy Markdown
Collaborator

@wesbillman wesbillman commented Apr 24, 2026

Summary

  • Day dividers: date separator headers in message lists, autolinked URLs, system message contrast, spacing improvements
  • Emoji picker: full emoji picker for message reactions
  • Video upload: Photo/Video chooser, native video transcoding for non-MP4 containers, fast-start MP4, silent audio loss + ANR fix on Android
  • Refactor: extract widgets from channel_detail_page (compose bar, manage channel sheet, members sheet, message actions), dedup upload logic
  • Test fixes: fix forum longPress hit-test warnings (IgnorePointer), skip video upload widget test that depends on native bridging

Test plan

  • All 257 tests pass (flutter test), no warnings
  • Video upload test skipped (native bridging dependency)
  • Manual: verify day dividers appear between messages on different days
  • Manual: verify emoji picker opens and reactions work
  • Manual: verify photo and video upload flow on iOS and Android

🤖 Generated with Claude Code

wesbillman and others added 9 commits April 23, 2026 11:03
…pacing

- Extract DayDivider to its own widget, add date_formatters with
  Today/Yesterday/weekday/full-date logic and isSameDay helper
- Flatten itemBuilder into a single Column with day-divider + system/regular
  message branching
- Convert <https://...> angle-bracket autolinks to tappable markdown links,
  skipping backtick-wrapped code segments
- Bump system message text from outline to onSurfaceVariant for readability;
  drop timestamp alpha
- Increase vertical spacing: grouped messages 2→4px, system rows 4→8px

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract emoji picker (categories, grid, show function) from compose_bar
into shared emoji_picker.dart. Add "+" button to the quick-reaction row
in the message long-press sheet that opens the full picker and fires
addReaction with the selected emoji.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add video upload to the mobile compose bar:
- MediaUploadService gains pickAndUploadVideo (MP4-only, matching relay)
- Paperclip button now shows Photo/Video chooser sheet
- Attachment strip shows video icon placeholder for video MIME types
- 100MB file size guard before reading video bytes into memory
- 5 new tests covering video upload, MIME detection, size limit, and
  compose bar video flow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…oads

Structural polish pass:
- Extract message_actions.dart (action sheet, edit, delete, reaction row)
- Extract members_sheet.dart (member list, role management, avatars)
- Extract manage_channel_sheet.dart (join/leave, canvas, context cards)
- channel_detail_page.dart reduced from 1877 to 1047 lines (-44%)
- Deduplicate pickAndUploadAttachment/pickAndUploadVideo into shared
  pickAndUpload helper in compose_bar.dart
- Remove dead imports after extraction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set shouldOptimizeForNetworkUse on AVAssetExportSession so the moov
atom is written at the front of the file. The relay rejects non-fast-start
MP4s with "moov atom not at front of file".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remux QuickTime .MOV and other non-MP4 video containers to MP4 before
uploading. Uses AVAssetExportSession (iOS) and MediaExtractor/MediaMuxer
(Android) for codec-copy remuxing — no re-encoding, near-instant.

- Add ftyp box detection to skip transcoding for already-MP4 files
- Read only first 32 bytes for container detection (avoids loading
  100MB into memory just to check format)
- File-path-based platform channel (not bytes) for large videos
- Temp file cleanup in finally blocks on all platforms
- Tests for ftyp detection, transcode path, and direct upload path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Select all tracks upfront and route samples by sampleTrackIndex instead
of processing tracks sequentially (which caused MediaExtractor EOF before
audio track was read). Move remux I/O to a background thread to prevent
ANR on larger video files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The upload spinner animation prevents pumpAndSettle from completing.
Use explicit pump cycles instead to advance through the async upload.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… test

Target ForumPostCard type instead of IgnorePointer-wrapped text for
tap/longPress finders. Skip video upload test that hangs due to native
platform bridging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wesbillman
Copy link
Copy Markdown
Collaborator Author

Screenshot 2026-04-24 at 9 20 15 AM

The expect() call with throwsA on an async function is non-blocking,
so the finally block could delete the temp file before pickAndUploadVideo
reads it. Use expectLater to await the assertion before cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wesbillman wesbillman merged commit 30adbad into main Apr 24, 2026
13 checks passed
@wesbillman wesbillman deleted the mobile-date-dividers branch April 24, 2026 16:32
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.

1 participant