commits
Like button: scale bounce animation (spring), crossfade icon, red (error) color when active
Repost button: scale bounce animation, crossfade icon, tertiary color when active
Repost long-press: heavy haptic confirms quote-post gesture registered
All action buttons (share, reply, like, repost): light haptic on tap
Follow/unfollow: confirmation haptic
Tab switching: light haptic
Scroll-to-top FABs: light haptic
Compose FAB: light haptic
Send post button: confirmation haptic
Content warning reveal: heavy haptic for deliberate action
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add error fallback to all AsyncImage calls so failed loads show placeholder instead of disappearing
- Bump Coil disk cache from 2% to 5%
- Fix session restore treating all errors as auth errors (only clear session on real auth failures)
- Fix mutex deadlock in create() using try/finally
- Close all one-off HttpClient instances to prevent resource leaks
- Add retry (3x exponential backoff) to all HTTP clients including login, PDS resolution, and uploads
- Bump video upload timeout to 5 minutes for mobile networks
- Increase all HTTP timeouts from 15s to 30s
- Clear error state after displaying snackbar to prevent stale errors
- Content warnings now show author info (avatar, name, handle) and only hide post content
- Highlight unread notifications with primaryContainer tint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create threadgate records after posting with configurable reply rules
(anyone, nobody, followers, following, mentioned)
- Shield icon in compose action row opens thread gate bottom sheet with
segmented buttons and checkboxes for reply rules
- Display "Replies limited" indicator on gated posts in timeline
- Add threadgate field to SkeetData, populate from PostView
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Track appview proxy as local mutable state so radio buttons update
immediately on selection
- Clear focus (dismiss keyboard) alongside hiding bottom sheet on back
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace .first {} with .firstOrNull {} in feeds() and
subscribedLabelers() to handle accounts without SavedFeedsPrefV2
or LabelersPref preferences
- Replace \!\! with safe returns in notification post lookups for
deleted/unavailable posts
- Avatar always renders and is long-pressable even when user profile
hasn't loaded yet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pass shared BlueskyConn to LoginView so new login writes to same
instance, then reset clients via onNewLogin() to force re-creation
- Clear nav back stack and reset firstLoadDone on login so data reloads
- Reduce top bar avatar from 55dp to 40dp
- Top bar avatar respects avatar shape setting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multi-account:
- Add AccountManager with DataStore persistence for multiple accounts
- Long-press profile avatar to open account switcher sheet
- Switch between accounts without re-logging in
- Add account button navigates to login
- Log out button in settings with account removal
- Auto-save account profile info after fetching self
Settings:
- Add appview selection (Bluesky/Blacksky/Custom) in settings
- Remove "via appview" label from feeds drawer
Content:
- Add post-level label content warnings with Show/Hide toggle
- Hydrate notification posts via getPosts for like/repost/reply counts
- Tapping "Reposted by" navigates to reposter's profile
UI fixes:
- Replace "See more" card with compact FilledTonalButton
- Profile view uses ElevatedCard with surfaceContainerLow
- Profile/Thread views use surface instead of background colors
- Consistent CircularWavyProgressIndicator across all views
- Compose view respects font size and avatar shape settings
- Back gesture dismisses compose bottom sheet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add post-level label support and content warning cards that hide
sensitive content behind a Show/Hide toggle for porn, sexual, nudity,
graphic-media, and gore labels
- Tapping "Reposted by" navigates to the reposter's profile
- Hide repost reason and labels in compose reply preview
- Pass postTextSize to compose view reply preview
- Back gesture/button dismisses compose bottom sheet
- Replace CircularProgressIndicator with CircularWavyProgressIndicator
in ProfileView and SearchView for consistent M3 expressive loading
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add settings page with 6 persisted options: theme mode, dynamic color,
post text size, avatar shape, reply filtering, show labels
- Move settings icon from top bar to own profile's top bar
- Thread postTextSize and avatarShape through embeds and compose view
- Fix missing facets in fromPostView (thread non-leaf posts)
- Fix video aspect ratio: use embed data to fill width proportionally
- Hide repost reason and labels in reply preview
- Fix label-to-body padding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New SettingsView with 6 persisted settings: theme mode (system/light/dark),
dynamic color toggle, post text size (S/M/L), avatar shape (circle/rounded),
reply filtering (none/normal/strict), and show labels toggle. Settings are
backed by DataStore and apply immediately across all views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pin timestamp to right edge of header row, truncate long names with
ellipsis. Replace SuggestionChip labels with compact Surface-based
chips using surfaceContainerHigh for less visual bulk.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pin timestamp to right edge of header row, truncate long names with
ellipsis. Replace SuggestionChip labels with compact Surface-based
chips using surfaceContainerHigh for less visual bulk.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use proper M3 tonal layering with surface/surfaceContainer colors,
ElevatedCards, SuggestionChips, left-aligned action buttons, inline
timestamps, and compact FlowRow notification avatars.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Display "via Bluesky" or "via Blacksky" (or the domain for unknown
appviews) under the "Feeds" title in the navigation rail drawer so
users know which appview they're connected through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The atproto-proxy header was set on all requests, but PDS procedures
(createRecord, deleteRecord, putRecord, uploadBlob, muteActor, etc.)
should not be proxied. When Blacksky was selected as appview, the PDS
tried to proxy writes to Blacksky which returned XRPCNotSupported.
Add a separate pdsClient without the proxy header for all PDS-native
calls. The appview client (with proxy header) is used only for queries
like getTimeline, getProfile, searchPosts, etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the from:user chip with a PersonSearch icon in the top bar
actions. Tapping it opens a dialog to enter a handle; when active, the
top bar title shows from:handle and the People tab is hidden. Tapping
the icon again clears the filter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switch search to Latest/Top/People tabs via PrimaryTabRow. Add a
from:user filter chip that opens an AlertDialog to enter a handle,
applying the from: query prefix to post searches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use M3 PrimaryTabRow with Posts, Replies, Media, Video tabs instead of
FilterChip pills for profile feed filtering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multiple notifications (likes, reposts, quotes) can reference the same
post, causing duplicate URIs in the getPosts batch request. This created
URLs too large for the 15s timeout. Add .distinct() to postsToFetch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove PrimaryTabRow and use a FilterChip pill for People alongside
the existing Latest/Top chips. Posts show by default, tapping People
toggles to the people results view.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add CLAUDE.md with project structure, build commands, architecture
patterns, and guidelines. Filter out posts whose CID already appears
as thread context (root/parent) of another post in the feed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement a search tab in the bottom navigation with M3 SearchBar,
PrimaryTabRow for Posts/People tabs, filter chips for Latest/Top sort
and from: author filter, pagination, and actor cards with verification
badges. Reuses SkeetView and Card for post results.
API: searchPosts (with sort, author filter) and searchActors on
BlueskyConn. ViewModel: search state, debounced search, pagination
methods, sort/author filter setters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix parent posts in timeline thread context not showing embeds by using
fromPostView (which uses the hydrated PostView.embed) instead of
fromPost (which manually converts from raw record and misses some types).
Also: route @mention taps to the profile viewer, only show "Profile not
found" when the API actually fails (not during loading), and track
profileNotFound state separately from null profile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only show the avatar and display name in the top bar after scrolling
past the profile header, avoiding redundant display of the username.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use AnimatedVisibility with fade + horizontal expand/shrink for the
avatar appearing in the top bar on scroll, instead of instant show/hide.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show the user's avatar next to display name in the top bar when the
profile header is scrolled out of view. Remove redundant center spinner
in favor of the existing PullToRefreshBox indicator. Overlap avatar on
banner in the edit profile sheet to match the profile view layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement a full profile screen reachable by tapping any user avatar.
Includes banner/avatar display, follow/unfollow, mute/unmute, bot badge,
verification badge, follower/following/post stats, bio, feed filter tabs
(posts, replies, media, video), pagination, and a profile editor bottom
sheet for own profile (edit display name, bio, avatar, banner). Also fix
ComposeView spell check by switching keyboard type from Email to Text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Like button: scale bounce animation (spring), crossfade icon, red (error) color when active
Repost button: scale bounce animation, crossfade icon, tertiary color when active
Repost long-press: heavy haptic confirms quote-post gesture registered
All action buttons (share, reply, like, repost): light haptic on tap
Follow/unfollow: confirmation haptic
Tab switching: light haptic
Scroll-to-top FABs: light haptic
Compose FAB: light haptic
Send post button: confirmation haptic
Content warning reveal: heavy haptic for deliberate action
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add error fallback to all AsyncImage calls so failed loads show placeholder instead of disappearing
- Bump Coil disk cache from 2% to 5%
- Fix session restore treating all errors as auth errors (only clear session on real auth failures)
- Fix mutex deadlock in create() using try/finally
- Close all one-off HttpClient instances to prevent resource leaks
- Add retry (3x exponential backoff) to all HTTP clients including login, PDS resolution, and uploads
- Bump video upload timeout to 5 minutes for mobile networks
- Increase all HTTP timeouts from 15s to 30s
- Clear error state after displaying snackbar to prevent stale errors
- Content warnings now show author info (avatar, name, handle) and only hide post content
- Highlight unread notifications with primaryContainer tint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Create threadgate records after posting with configurable reply rules
(anyone, nobody, followers, following, mentioned)
- Shield icon in compose action row opens thread gate bottom sheet with
segmented buttons and checkboxes for reply rules
- Display "Replies limited" indicator on gated posts in timeline
- Add threadgate field to SkeetData, populate from PostView
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace .first {} with .firstOrNull {} in feeds() and
subscribedLabelers() to handle accounts without SavedFeedsPrefV2
or LabelersPref preferences
- Replace \!\! with safe returns in notification post lookups for
deleted/unavailable posts
- Avatar always renders and is long-pressable even when user profile
hasn't loaded yet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Pass shared BlueskyConn to LoginView so new login writes to same
instance, then reset clients via onNewLogin() to force re-creation
- Clear nav back stack and reset firstLoadDone on login so data reloads
- Reduce top bar avatar from 55dp to 40dp
- Top bar avatar respects avatar shape setting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Multi-account:
- Add AccountManager with DataStore persistence for multiple accounts
- Long-press profile avatar to open account switcher sheet
- Switch between accounts without re-logging in
- Add account button navigates to login
- Log out button in settings with account removal
- Auto-save account profile info after fetching self
Settings:
- Add appview selection (Bluesky/Blacksky/Custom) in settings
- Remove "via appview" label from feeds drawer
Content:
- Add post-level label content warnings with Show/Hide toggle
- Hydrate notification posts via getPosts for like/repost/reply counts
- Tapping "Reposted by" navigates to reposter's profile
UI fixes:
- Replace "See more" card with compact FilledTonalButton
- Profile view uses ElevatedCard with surfaceContainerLow
- Profile/Thread views use surface instead of background colors
- Consistent CircularWavyProgressIndicator across all views
- Compose view respects font size and avatar shape settings
- Back gesture dismisses compose bottom sheet
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add post-level label support and content warning cards that hide
sensitive content behind a Show/Hide toggle for porn, sexual, nudity,
graphic-media, and gore labels
- Tapping "Reposted by" navigates to the reposter's profile
- Hide repost reason and labels in compose reply preview
- Pass postTextSize to compose view reply preview
- Back gesture/button dismisses compose bottom sheet
- Replace CircularProgressIndicator with CircularWavyProgressIndicator
in ProfileView and SearchView for consistent M3 expressive loading
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add settings page with 6 persisted options: theme mode, dynamic color,
post text size, avatar shape, reply filtering, show labels
- Move settings icon from top bar to own profile's top bar
- Thread postTextSize and avatarShape through embeds and compose view
- Fix missing facets in fromPostView (thread non-leaf posts)
- Fix video aspect ratio: use embed data to fill width proportionally
- Hide repost reason and labels in reply preview
- Fix label-to-body padding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New SettingsView with 6 persisted settings: theme mode (system/light/dark),
dynamic color toggle, post text size (S/M/L), avatar shape (circle/rounded),
reply filtering (none/normal/strict), and show labels toggle. Settings are
backed by DataStore and apply immediately across all views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use proper M3 tonal layering with surface/surfaceContainer colors,
ElevatedCards, SuggestionChips, left-aligned action buttons, inline
timestamps, and compact FlowRow notification avatars.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The atproto-proxy header was set on all requests, but PDS procedures
(createRecord, deleteRecord, putRecord, uploadBlob, muteActor, etc.)
should not be proxied. When Blacksky was selected as appview, the PDS
tried to proxy writes to Blacksky which returned XRPCNotSupported.
Add a separate pdsClient without the proxy header for all PDS-native
calls. The appview client (with proxy header) is used only for queries
like getTimeline, getProfile, searchPosts, etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the from:user chip with a PersonSearch icon in the top bar
actions. Tapping it opens a dialog to enter a handle; when active, the
top bar title shows from:handle and the People tab is hidden. Tapping
the icon again clears the filter.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement a search tab in the bottom navigation with M3 SearchBar,
PrimaryTabRow for Posts/People tabs, filter chips for Latest/Top sort
and from: author filter, pagination, and actor cards with verification
badges. Reuses SkeetView and Card for post results.
API: searchPosts (with sort, author filter) and searchActors on
BlueskyConn. ViewModel: search state, debounced search, pagination
methods, sort/author filter setters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix parent posts in timeline thread context not showing embeds by using
fromPostView (which uses the hydrated PostView.embed) instead of
fromPost (which manually converts from raw record and misses some types).
Also: route @mention taps to the profile viewer, only show "Profile not
found" when the API actually fails (not during loading), and track
profileNotFound state separately from null profile.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show the user's avatar next to display name in the top bar when the
profile header is scrolled out of view. Remove redundant center spinner
in favor of the existing PullToRefreshBox indicator. Overlap avatar on
banner in the edit profile sheet to match the profile view layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement a full profile screen reachable by tapping any user avatar.
Includes banner/avatar display, follow/unfollow, mute/unmute, bot badge,
verification badge, follower/following/post stats, bio, feed filter tabs
(posts, replies, media, video), pagination, and a profile editor bottom
sheet for own profile (edit display name, bio, avatar, banner). Also fix
ComposeView spell check by switching keyboard type from Email to Text.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>