···11+---
22+title: Bugs (Post Actions & Notifications — Fix Specification)
33+updated: 2026-03-17
44+---
55+66+## Checklist
77+88+- [ ] [1. Post Thread Screen](#1-post-thread-screen)
99+- [ ] [2. Post Tap Navigation](#2-post-tap-navigation)
1010+- [ ] [3. Avatar Tap Navigation](#3-avatar-tap-navigation)
1111+- [ ] [4. Quoted Post Tap Navigation](#4-quoted-post-tap-navigation)
1212+- [ ] [5. Notification Tap Navigation](#5-notification-tap-navigation)
1313+- [ ] [6. Viewer State on Own Posts](#6-viewer-state-on-own-posts)
1414+- [ ] [7. Saved Posts Screen — Render Actual Posts](#7-saved-posts-screen--render-actual-posts)
1515+- [ ] [8. Saved Posts — Accessible from Profile](#8-saved-posts--accessible-from-profile)
1616+- [ ] [9. Saved Posts — Long Press for Local, Tap for Menu](#9-saved-posts--long-press-for-local-tap-for-menu)
1717+- [ ] [10. Saved Posts — Show Save Counts](#10-saved-posts--show-save-counts)
1818+- [ ] [11. Failed Action Snackbar with Revert](#11-failed-action-snackbar-with-revert)
1919+- [ ] [12. Delete Post — Remove from Feed](#12-delete-post--remove-from-feed)
2020+2121+## 1. Post Thread Screen
2222+2323+**Status:** Missing — no `/post` route or screen exists.
2424+2525+**Problem:** Multiple features navigate to `/post?uri=...` or `/post/{uri}`, but the
2626+route is not defined in `app_router.dart` and no screen exists. This breaks:
2727+2828+- Notification taps (like, repost, reply, mention, quote)
2929+- Saved post "open" action
3030+- Any future post deeplink
3131+3232+**Fix:**
3333+3434+- Create `lib/features/feed/presentation/post_thread_screen.dart`.
3535+- Use `designs/thread.html` as a reference for the UI.
3636+- Use the Bluesky `getPostThread` API to fetch the thread (parent chain + replies).
3737+- Display the focused post with full content plus its parent posts above and replies
3838+ below, each rendered as `PostCardWithActions`.
3939+- Register route in `app_router.dart`:
4040+ - Path: `/post` with query param `uri` (e.g. `/post?uri=at://...`).
4141+- Handle loading, error, and blocked/not-found thread states.
4242+4343+**Files:**
4444+4545+- New: `lib/features/feed/presentation/post_thread_screen.dart`
4646+- New: `lib/features/feed/data/post_thread_repository.dart` (wraps `getPostThread`)
4747+- Edit: `lib/core/router/app_router.dart` — add `/post` route
4848+4949+## 2. Post Tap Navigation
5050+5151+**Status:** Broken — tapping a post body does nothing.
5252+5353+**Problem:** `PostCard` is not wrapped in a tap detector. The only interactive elements
5454+are the action bar buttons and embedded media. Users expect tapping a post to open it.
5555+5656+**Fix:**
5757+5858+- Wrap the post content area (header + text + embed, excluding the action bar) in an
5959+ `InkWell` that navigates to `/post?uri={postUri}`.
6060+- The action bar itself should NOT trigger navigation — only the content area above it.
6161+6262+**Files:**
6363+6464+- Edit: `lib/features/feed/presentation/widgets/post_card.dart` — wrap content in
6565+ `InkWell` with navigation callback
6666+- Edit: `lib/features/feed/presentation/widgets/post_card_with_actions.dart` — pass
6767+ `onTap` callback through to `PostCard`
6868+6969+## 3. Avatar Tap Navigation
7070+7171+**Status:** Broken — tapping a post author's avatar does nothing.
7272+7373+**Problem:** The avatar `CircleAvatar` in `PostCard._buildHeader` is not tappable.
7474+Users expect tapping an avatar to navigate to that user's profile.
7575+7676+**Fix:**
7777+7878+- Wrap the `CircleAvatar` in `_buildHeader` with a `GestureDetector` that navigates to
7979+ `/profile/view?actor={author.did}`.
8080+- Requires passing the navigation callback or `BuildContext` with router access.
8181+8282+**Files:**
8383+8484+- Edit: `lib/features/feed/presentation/widgets/post_card.dart` — `_buildHeader`
8585+ (line ~55)
8686+8787+## 4. Quoted Post Tap Navigation
8888+8989+**Status:** Incorrect — tapping a quoted post navigates to the quoted author's profile
9090+instead of the quoted post.
9191+9292+**Problem:** `PostCard._buildQuotedRecord` (line 342-346) navigates to
9393+`/profile/view?actor={quoted.author.did}`. It should open the quoted post in the thread
9494+screen.
9595+9696+**Fix:**
9797+9898+- Change the `onTap` in `_buildQuotedRecord` to navigate to
9999+ `/post?uri={quoted.uri}` instead of the author's profile.
100100+101101+**Files:**
102102+103103+- Edit: `lib/features/feed/presentation/widgets/post_card.dart` — `_buildQuotedRecord`
104104+ (line ~342)
105105+106106+## 5. Notification Tap Navigation
107107+108108+**Status:** Broken — tapping non-follow notifications crashes or does nothing (route
109109+doesn't exist).
110110+111111+**Problem:** `notification_list_item.dart:263` pushes `/post?uri=...` but the route is
112112+undefined. This is blocked by [#1](#1-post-thread-screen).
113113+114114+**Fix:**
115115+116116+- Once the `/post` route exists ([#1](#1-post-thread-screen)), notification taps will
117117+ work. Verify the URI encoding is consistent (`Uri.encodeComponent` vs query param).
118118+- Current code: `context.push('/post?uri=${Uri.encodeComponent(uri.toString())}')`
119119+- Ensure the route handler decodes this correctly.
120120+- For like/repost notifications, `notification.uri` may point to the *liker's record*,
121121+ not the original post. Verify that `reasonSubject` (the post that was liked) is used
122122+ instead when appropriate.
123123+124124+**Files:**
125125+126126+- Edit: `lib/features/notifications/presentation/widgets/notification_list_item.dart`
127127+ — `_onTap` (line ~256). May need to use `notification.reasonSubject` for like/repost
128128+ notifications instead of `notification.uri`.
129129+130130+## 6. Viewer State on Own Posts
131131+132132+**Status:** Broken — current user's liked/reposted/saved posts don't show as active in
133133+the feed.
134134+135135+**Problem:** `PostCardWithActions` initializes `PostActionCubit` from `viewer.like` and
136136+`viewer.repost` (lines 35-36), which correctly reflects the API state. However:
137137+138138+- After the user likes a post, scrolls away, and scrolls back, the cubit is recreated
139139+ from the stale `FeedViewPost` data (the original API response), losing the local
140140+ optimistic state.
141141+- Saved state works correctly because `SavedPostsCubit` is global and checks the DB.
142142+143143+**Fix:**
144144+145145+- Maintain a lightweight in-memory cache (e.g. `Map<String, PostActionState>`) in a
146146+ higher-level provider that `PostActionCubit` reads from on creation and writes to on
147147+ state changes. This way, scrolling away and back preserves the user's actions within
148148+ the session.
149149+- Alternatively, store the `likeUri`/`repostUri` in the feed bloc state so it survives
150150+ cubit recreation.
151151+152152+**Files:**
153153+154154+- New or edit: A post action cache/provider (could be a simple `ChangeNotifier` or
155155+ cubit at the feed level)
156156+- Edit: `lib/features/feed/presentation/widgets/post_card_with_actions.dart` — read
157157+ from cache on cubit creation
158158+- Edit: `lib/features/feed/cubit/post_action_cubit.dart` — write to cache on state
159159+ changes
160160+161161+## 7. Saved Posts Screen — Render Actual Posts
162162+163163+**Status:** Incomplete — saved posts screen shows metadata cards, not the actual post
164164+content.
165165+166166+**Problem:** `_SavedPostCard` in `saved_posts_screen.dart` shows a generic "Saved Post"
167167+`ListTile` with a date and action buttons. The full post JSON is stored in the DB
168168+(`postJson` column) but is never deserialized and rendered.
169169+170170+**Fix:**
171171+172172+- Deserialize `savedPost.postJson` back into a `PostView` and render it with
173173+ `PostCardWithActions` (or a read-only variant).
174174+- The "open" button should navigate to `/post?uri={postUri}` (once [#1](#1-post-thread-screen) exists).
175175+- Keep swipe-to-dismiss for unsaving.
176176+177177+**Files:**
178178+179179+- Edit: `lib/features/feed/presentation/saved_posts_screen.dart` — replace
180180+ `_SavedPostCard` with actual post rendering
181181+- The route in `_openPost` (line 186) currently uses path-style
182182+ `/post/${Uri.encodeComponent(...)}` but should use query-style
183183+ `/post?uri=${Uri.encodeComponent(...)}` to match the route definition.
184184+185185+## 8. Saved Posts — Accessible from Profile
186186+187187+**Status:** Incorrect location — saved posts are behind Settings, not on profiles.
188188+189189+**Problem:** The saved posts link is in `settings_screen.dart` (line 56-61). The
190190+requirement is that it should be accessible from profiles.
191191+192192+**Fix:**
193193+194194+- Add a "Saved Posts" button/tab on the current user's own profile screen.
195195+- Keep (or remove) the Settings entry as a secondary access point.
196196+197197+**Files:**
198198+199199+- Edit: profile screen (add saved posts navigation for the current user's profile)
200200+- Optionally edit: `lib/features/settings/presentation/settings_screen.dart`
201201+202202+## 9. Saved Posts — Long Press for Local, Tap for Menu
203203+204204+**Status:** Missing — only tap-to-toggle exists, no long press or menu.
205205+206206+**Problem:** The bookmark button in `PostActionBar` only has `onTap` (line 82). The
207207+requirement is:
208208+209209+- **Long press** → save/unsave locally (instant, different icon color)
210210+- **Normal press** → show menu with options: save/remove locally, save/remove from
211211+ cloud (ATProto)
212212+213213+Cloud save is not yet implemented, but the menu structure should be in place.
214214+215215+**Fix:**
216216+217217+- Add `onLongPress` to the bookmark `_ActionButton` in `PostActionBar`.
218218+- Long press: toggle local save immediately (current behavior), use a distinct color
219219+ (e.g. amber/gold for local saves vs primary for cloud).
220220+- Normal press: show a bottom sheet with options:
221221+ - "Save locally" / "Remove local save"
222222+ - "Save to Bluesky" / "Remove from Bluesky" (disabled/placeholder until cloud is
223223+ implemented)
224224+- Update `SavedPostsState` to distinguish local vs cloud saves.
225225+226226+**Files:**
227227+228228+- Edit: `lib/features/feed/presentation/widgets/post_action_bar.dart` — add
229229+ `onLongPress`, show menu on tap
230230+- Edit: `lib/features/feed/cubit/saved_posts_cubit.dart` — support save type
231231+ distinction
232232+- Edit: `lib/core/database/tables.dart` — add `saveType` column (local/cloud/both)
233233+ with migration
234234+235235+## 10. Saved Posts — Show Save Counts
236236+237237+**Status:** Missing — hardcoded to `0` and hidden.
238238+239239+**Problem:** `PostActionBar` line 80: `count: 0` for the bookmark button. Save counts
240240+are never fetched or displayed.
241241+242242+**Fix:**
243243+244244+- The Bluesky API provides `PostView.bookmarkCount` (nullable `int`). Pass this value
245245+ through to `PostActionBar` instead of the hardcoded `0`.
246246+- Wire it up the same way `likeCount`/`repostCount` are: read from `post.bookmarkCount`
247247+ in `PostCardWithActions` and pass to `PostActionBar`.
248248+249249+**Files:**
250250+251251+- Edit: `lib/features/feed/presentation/widgets/post_card_with_actions.dart` — read
252252+ `post.bookmarkCount ?? 0` and pass to action bar
253253+- Edit: `lib/features/feed/presentation/widgets/post_action_bar.dart` — use the passed
254254+ count instead of hardcoded `0`
255255+256256+## 11. Failed Action Snackbar with Revert
257257+258258+**Status:** Partially implemented — rollback works but snackbar is basic.
259259+260260+**Problem:** `PostActionCubit` correctly reverts optimistic updates on failure and shows
261261+a snackbar via `BlocListener` in `post_card_with_actions.dart` (lines 55-64). However:
262262+263263+- The snackbar has no retry action button.
264264+- There's no visual indication during the loading state (the icon just sits there while
265265+ `isLoadingLike`/`isLoadingRepost` is true).
266266+267267+**Fix:**
268268+269269+- Add a "Retry" `SnackBarAction` to the error snackbar.
270270+- Show a subtle loading indicator on the action button while the network call is
271271+ in-flight (e.g., replace the icon with a small spinner, or dim it). The
272272+ `isLoadingLike`/`isLoadingRepost` fields already exist in state.
273273+274274+**Files:**
275275+276276+- Edit: `lib/features/feed/presentation/widgets/post_card_with_actions.dart` — add
277277+ retry action to snackbar
278278+- Edit: `lib/features/feed/presentation/widgets/post_action_bar.dart` — show loading
279279+ state visually on like/repost buttons
280280+281281+## 12. Delete Post — Remove from Feed
282282+283283+**Status:** Incomplete — post is deleted on the server but remains visible in the feed.
284284+285285+**Problem:** `PostActionCubit.deletePost()` (line 186-193) calls the API to delete but
286286+does not remove the post from the feed list. The deleted post card remains visible until
287287+the user refreshes.
288288+289289+**Fix:**
290290+291291+- After successful deletion, notify the parent feed bloc/cubit to remove the post from
292292+ its list.
293293+- This could be done via a callback, a shared event bus, or by having the feed bloc
294294+ listen for deletion events.
295295+- Show a confirmation snackbar: "Post deleted".
296296+297297+**Files:**
298298+299299+- Edit: `lib/features/feed/cubit/post_action_cubit.dart` — emit a "deleted" state or
300300+ invoke a callback
301301+- Edit: feed bloc/cubit — handle post removal from list
302302+- Edit: `lib/features/feed/presentation/widgets/post_card_with_actions.dart` — wire up
303303+ deletion callback
-4
docs/TODO.md
···1414- Instead of tabs, navigating to a record through dev tools should instead show
1515 - A drawer on Tablet
1616 - Cards (stacked) on Mobile, with swipe to go back
1717-- Post interactions are off -> selecting a quoted post opens that user's profile.
1818- - Tapping a post doesn't doesn't go to the post
1919- - Tapping a user's avatar in a post doesn't go to their profile
2020- - We need to add a post screen that renders a thread
21172218## Enhancements
2319