Skip to content

feat(locks): add the Unlocked profile screen (#2005) - #2301

Draft
Taewa wants to merge 5 commits into
feat/2003-locks-reader-integrationfrom
feat/2005-locks-unlocked-profile
Draft

feat(locks): add the Unlocked profile screen (#2005)#2301
Taewa wants to merge 5 commits into
feat/2003-locks-reader-integrationfrom
feat/2005-locks-unlocked-profile

Conversation

@Taewa

@Taewa Taewa commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #2005. Part of #1998, stacked on #2003base is feat/2003-locks-reader-integration, review that first. Draft until #2252 merges.

What this adds

  • A screen at /profile/unlocked listing the content the signed-in reader has unlocked, newest first.
  • An Unlocked entry with a count in the profile sidebar and the mobile menu. Own profile only — the data lives in the reader's /priv, so another user's profile has none.
  • Cards that render like the feed does: article titles, images, videos, file downloads, link embeds. Reuses the existing post renderers rather than adding lock-specific ones.

Behaviour worth knowing

  • One read per profile visit. The profile layout survives tab navigation, so the sidebar count and the screen share a single read instead of enumerating /priv twice.
  • Media loads per card, and is released when the card unmounts. Loading every attachment up front would pull the reader's whole unlocked library onto one screen.
  • Interrupted replications never appear. A lock only counts once its completion marker is stored.
  • A corrupt or missing entry drops on its own — the rest of the list still renders. A transient failure fails the whole read instead, so an outage doesn't look like lost content.
  • Ordered by the homeserver's write time, not a timestamp the client writes into the file.
  • Long posts expand in place. An unlocked copy has no post page to open, so "Show more" would otherwise do nothing. Existing feed cards are unaffected — they still navigate.

Not in scope

Notes for review

  • No pagination — the list loads in full, matching the ticket.
  • docs/locks.md has a new section covering the flow and the decisions above.

- List the content the signed-in reader has unlocked at /profile/unlocked, newest first
- Add an Unlocked entry with a count to the profile sidebar and the mobile menu, own profile only
- Render each unlocked post the way the feed does: article titles, images, videos, file downloads, link embeds
- Read the list once per profile visit and share it between the sidebar count and the screen
- Load a post's media only when its card renders, and release it when the card goes away
- Skip locks whose replication never finished, and drop a corrupt or missing entry instead of failing the whole list
- Order by the homeserver's write time rather than a timestamp the client puts in the file
- Expand long posts in place, since an unlocked copy has no post page to open
@Taewa Taewa self-assigned this Aug 5, 2026
@Taewa Taewa added the locks Locks feature (content access control) label Aug 5, 2026
@Taewa Taewa added this to the Lugano - 2026 milestone Aug 5, 2026
Taewa added 3 commits August 6, 2026 00:13
- Keep the title when locking an article, so the unlocked copy can show it — it was dropped before and    could not be recovered
- Render an unlocked article with its title and cover image in the feed, instead of plain body text
- Same fix reaches the creator viewing their own locked article, which reads through the same path
- Articles locked before this still render as body text rather than breaking
@Taewa

Taewa commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

https://github.com/pubky/pubky-homeserver/blob/1106eb02360b0bce88b0a6136f85f20308caebac/pubky-sdk/bindings/js/pkg/tests/events.ts#L110 <- This should be used instead of list() because this fn returns as chronological order / reversed.

@Taewa
Taewa requested review from tipogi and removed request for tipogi August 7, 2026 10:07
…d-profile

Brings in the 18 reader commits this branch was missing, including the 2026
creator work that the previous two merges added to the reader branch.

Three conflicts, all resolved by combining both sides rather than picking one:

- HomeserverService.getBytesIfExists — this branch had added the Last-Modified
  timestamp so the unlocked list can sort by it, and the reader branch had made
  only a 404 mean "absent". Both are kept: the 404 check and assertOk run first,
  then the result carries bytes and modifiedAt.
- The tests for that method — both sides wrote their own set. Both sets are kept
  and share one URL constant, and the reader branch's assertion now reads
  result.bytes instead of the old plain Uint8Array.
- locks.test.ts imports — the union of both sides, since all three error codes
  are used.

LockedPostContent.test.tsx still called mockUsePostLock, which f6cc872 had
replaced with mockLockData. The two calls added on this branch now use the new
helper; the signature is the same.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

locks Locks feature (content access control)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant