Skip to content

Promote WenWe/Accelerate utilities: paging de-dupe, serialization-safe Compose state, clipboard copier (1.6.3) - #101

Merged
projectdelta6 merged 5 commits into
mainfrom
dev/wenwe-accelerate-toolbox-utilities
Jul 22, 2026
Merged

Promote WenWe/Accelerate utilities: paging de-dupe, serialization-safe Compose state, clipboard copier (1.6.3)#101
projectdelta6 merged 5 commits into
mainfrom
dev/wenwe-accelerate-toolbox-utilities

Conversation

@projectdelta6

@projectdelta6 projectdelta6 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Promotes three fully-generic utilities out of WenWe Android and Accelerate Android into the toolbox, per docs/proposed/paging-dedupe-and-serializable-compose-state.md (the proposal doc that specified this work is removed in this PR now that it is implemented and WenWe + Accelerate have been migrated).

What's added

Utility Module Package
Flow<PagingData<T>>.distinctBy(selector) :PagingExtensions uk.co.appoly.droid.util.paging
SerializableMutableState / TransientMutableState (+ factories) :ComposeExtensions uk.co.appoly.droid.compose.extensions
ClipboardCopier + rememberClipboardCopier() + copyX extensions :ComposeExtensions uk.co.appoly.droid.compose.extensions
  • distinctBy — guards LazyColumn/LazyRow against IllegalArgumentException: Key "…" was already used when an offset-paged endpoint returns the same item id on more than one page. De-dupes by an arbitrary key, first occurrence wins, seen set resets per PagingData generation.
  • Serialization-safe state holdersSerializable MutableState for Voyager Screens (which are Java-serialized across process death). Drop-in for by/.value/destructuring. SerializableMutableState persists & restores; TransientMutableState resets to initial on restore.
  • ClipboardCopier — wraps the suspend LocalClipboard API (the LocalClipboardManager replacement): remembered scope, confirmation fires only after the write returns, and the app's own toast is gated to Android < 13 (API 33+ shows its own).

The release-only crash this fixes

The WenWe originals risked a release-only NPE after process death: consumer R8 strips the reflectively-invoked writeObject/readObject, default serialization then persists nothing (the only field is @Transient), and the value restores as null. Fixes applied for the library:

  • Scoped consumer ProGuard keep rules in ComposeExtensions/consumer-rules.pro (package-scoped, not class *).
  • Fail-fast require(Serializable-or-null) at construction and on assignment, with the writeObject throw kept as a backstop.
  • Dropped the meaningless BuildConfig.DEBUG gate and internal ticket IDs from published KDoc.

Testing

  • 21 new tests, all green — 3 paging (asSnapshot), 7 + 4 state-holder round-trip, 7 clipboard (Robolectric SDK-gating + CompletableDeferred-gated ordering).
  • The new consumer keep rules are regression-guarded: a new ComposeExtensionsDemoScreen exercises the holders in the minified demo app so :app:verifyConsumerKeepRules proves the rule fires against a real R8 consumer — protected-class count 27 → 29. ✓

Notes

  • Version bumped to 1.6.3; all README versions synced via UpdateReadmeVersions.
  • New ComposeExtensions/README.md; root README module entries added for ComposeExtensions & PagingExtensions.
  • App-side migrations in WenWe + Accelerate (deleting local copies, repointing imports) are done; the proposal doc is removed here (its history stays on develop).

🤖 Generated with Claude Code

projectdelta6 and others added 4 commits July 21, 2026 12:51
Capture two generic utilities written in WenWe (fixing Sentry
WENWE-ANDROID-5H and 5G) as a proposed-features TODO, ready to lift in:
- Flow<PagingData<T>>.distinctBy → :PagingExtensions
- SerializableMutableState / TransientMutableState → :ComposeExtensions

Includes copy-paste-ready source (repackaged), placement, a note that the
library must not rely on BuildConfig.DEBUG for the fail-fast guard, tests to
add, and a checklist to migrate WenWe onto the lib versions once released.

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

Docs/proposed wenwe utility promotions
…opier

Promote three generic utilities out of WenWe and Accelerate into the toolbox
(see docs/proposed/paging-dedupe-and-serializable-compose-state.md):

- :PagingExtensions — Flow<PagingData<T>>.distinctBy(selector) guards LazyColumn/
  LazyRow against duplicate keys when an offset-paged endpoint returns the same
  item id on more than one page.
- :ComposeExtensions — SerializableMutableState / TransientMutableState (+ factories),
  Serializable MutableState holders for Voyager Screens. Fixed the release-only NPE
  the WenWe originals risked: consumer R8 stripped the reflective writeObject/readObject
  so the value restored as null. Added scoped consumer keep rules, plus fail-fast
  require() on construction and assignment (writeObject throw kept as a backstop).
- :ComposeExtensions — ClipboardCopier + rememberClipboardCopier() + copyX extensions,
  wrapping the suspend LocalClipboard API and gating the confirmation toast to
  Android < 13 (API 33+ shows its own).

Tests: 21 new unit/Robolectric tests (all green). The consumer keep rules are
regression-guarded by :app:verifyConsumerKeepRules via a new ComposeExtensionsDemoScreen
that exercises the holders in the minified demo app (27 -> 29 protected classes).

Version bumped to 1.6.3; README versions synced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6 projectdelta6 self-assigned this Jul 22, 2026
The three utilities shipped in 1.6.3 and WenWe + Accelerate have been migrated
to the library versions per the doc's instructions, so the proposal scaffolding
is no longer needed. History remains on develop (commits 4f7e3b8, f4e5dcf).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@projectdelta6
projectdelta6 merged commit 9a2c18d into main Jul 22, 2026
1 check passed
@projectdelta6
projectdelta6 deleted the dev/wenwe-accelerate-toolbox-utilities branch July 22, 2026 13:33
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