mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

docs: add changelog

+64 -202
+42
CHANGELOG.md
··· 1 + # CHANGELOG 2 + 3 + ## v0.1.0 (Unreleased) 4 + 5 + ### Added 6 + 7 + #### 2026-03-16 8 + 9 + - OAuth2 authentication flow (app password for debugging) 10 + - Theming - Oxocarbon, Rose Pine, Nord, Catppuccin 11 + 12 + #### 2026-03-17 13 + 14 + - Profile screen (post viewing) 15 + - Feed view and management screens (reordering & pinning) 16 + - Post actions (like, reply, repost) 17 + - Local and ATProto/cloud saving of posts 18 + 19 + #### 2026-03-18 20 + 21 + - Post composer with persisted drafts 22 + - Post deletion 23 + - "Dev Tools" -> view logs and explore PDS records ([pdsls](https://pds.ls)) style 24 + 25 + #### 2026-03-19 26 + 27 + - Notification viewing 28 + - Search screen for posts and users 29 + - Jump to profile action from search screen with autocomplete 30 + - Direct messages and requests 31 + - Media players and downloading of images and videos 32 + 33 + #### 2026-03-20 34 + 35 + - Post thread screen 36 + - Threaded replies with collapse/expand 37 + - Auto-collapse replies after a certain depth 38 + 39 + #### 2026-03-21 40 + 41 + - Moderation service integration 42 + - Labels added to users in posts
+4 -28
docs/tasks/phase-1.md
··· 2 2 3 3 ## M0 — Project Scaffolding 4 4 5 - - [x] Add dependencies (`bluesky`, `atproto_oauth`, `bluesky_text`, `flutter_bloc`, `drift`, `go_router`) 6 - - [x] Set up feature-first folder structure (`core/`, `features/auth|profile|settings/`) 7 - - [x] Configure Drift database with `accounts`, `cached_profiles`, `cached_posts`, `settings` tables 8 - - [x] Configure `go_router` with initial route definitions (login, home, profile, settings) 5 + Completed [2026-03-16](../../CHANGELOG.md#2026-03-16) 9 6 10 7 ## M1 — Authentication 11 8 12 - - [x] Implement App Password login (`createSession`) behind `kDebugMode` flag 13 - - [x] Implement OAuth 2.0 flow (DPoP + PAR + PKCE) via `atproto_oauth` 14 - - [x] Set up loopback redirect listener (`http://127.0.0.1/callback`) 15 - - [x] Build `AuthBloc` — events: `LoginRequested`, `LogoutRequested`, `SessionRestored`; states: `Unauthenticated`, `Authenticating`, `Authenticated`, `AuthError` 16 - - [x] Session persistence: store/restore tokens in Drift, silent refresh on launch 17 - - [x] Build login screen (handle input, OAuth button, debug app-password form) 18 - - [x] Logout: revoke tokens, clear Drift row, reset Bloc, navigate to login 9 + Completed [2026-03-16](../../CHANGELOG.md#2026-03-16) 19 10 20 11 ## M2 — Profile Rendering 21 12 22 - - [x] Build `ProfileBloc` — fetch via `getProfile` / `getProfiles` 23 - - [x] Profile screen: avatar, banner, display name, handle, description, stats (followers/following/posts), pronouns, website 24 - - [x] Build `FeedBloc` — paginated fetch via `getAuthorFeed` with cursor + filter support 25 - - [x] Post card widget: text, timestamps, embeds (images, quote posts, link cards) 26 - - [x] Facet rendering: parse via `bluesky_text`, render mentions / links / hashtags as tappable spans (UTF-8 byte-safe) 13 + Completed [2026-03-17](../../CHANGELOG.md#2026-03-17) 27 14 28 15 ## M3 — Settings & Theming 29 16 30 - - [x] `SettingsCubit` backed by Drift — theme mode preference (system / light / dark) 31 - - [x] Oxocarbon Dark `ThemeData` / `ColorScheme` 32 - - [x] Oxocarbon Light `ThemeData` / `ColorScheme` 33 - - [x] Catppuccin Mocha (Dark) `ThemeData` / `ColorScheme` 34 - - [x] Catppuccin Latte (Light) `ThemeData` / `ColorScheme` 35 - - [x] Nord Polar Night (Dark) `ThemeData` / `ColorScheme` 36 - - [x] Nord Snow Storm (Light) `ThemeData` / `ColorScheme` 37 - - [x] Rosé Pine Main (Dark) `ThemeData` / `ColorScheme` 38 - - [x] Rosé Pine Dawn (Light) `ThemeData` / `ColorScheme` 39 - - [x] Theme picker in settings screen (all 4 palettes × 2 variants + system) 40 - - [x] Respect system theme when set to "system" 41 - - NOTE: sans font changed to dmsans from geist 17 + Completed [2026-03-16](../../CHANGELOG.md#2026-03-16)
+4 -38
docs/tasks/phase-2.md
··· 2 2 3 3 ## M4 — Logging 4 4 5 - - [x] Add `logger` package dependency 6 - - [x] `AppLogger` wrapper — singleton with `DevelopmentFilter` + `PrettyPrinter` for console, `AdvancedFileOutput` + `SimplePrinter` for file 7 - - [x] File rotation — daily log files in app documents dir (`lazurite_YYYY-MM-DD.log`), 3-day retention 8 - - [x] `LoggingBlocObserver` — log BLoC state transitions at `debug` level 9 - - [x] HTTP logging interceptor — request/response summaries, redact `Authorization` header, truncate bodies 10 - - [x] `NavigatorObserver` subclass — log route changes at `info` level 11 - - [x] Log viewer screen — scrollable list reading from log files on disk 12 - - [x] Level filter chip bar — toggle visibility per log level 13 - - [x] Free-text search across log messages 14 - - [x] Share button — export current day's log file via system share sheet 15 - - [x] Clear all logs with confirmation dialog 16 - - [x] Add "Logs" entry under Dev Tools in Settings screen 5 + Completed [2026-03-18](../../CHANGELOG.md#2026-03-18) 17 6 18 7 ## M5 — Feeds 19 8 20 - - [x] Build home screen with horizontally-swipable tab bar (one tab per pinned feed) 21 - - [x] Implement timeline feed via `getTimeline` with cursor pagination 22 - - [x] Implement feed generator rendering via `getFeed` (AT-URI + pagination) 23 - - [x] `FeedPreferencesCubit` — read/write `savedFeedsPrefV2` via `getPreferences` / `putPreferences` 24 - - [x] Cache feed preferences in Drift for offline access 25 - - [x] Feed discovery screen via `getSuggestedFeeds` — browse and add generators 26 - - [x] Feed management UI — pin/unpin, drag-to-reorder, remove saved feeds 9 + Completed [2026-03-18](../../CHANGELOG.md#2026-03-18) 27 10 28 11 ## M6 — Search 29 12 30 - - [x] Search screen with text input, sort toggle (`top` / `latest`), and result tabs (posts / actors) 31 - - [x] `SearchBloc` — events: `QuerySubmitted`, `TypeaheadRequested`, `HistoryCleared`, `HistoryEntryDeleted` 32 - - [x] Post search via `searchPosts` with paginated results 33 - - [x] Actor search via `searchActors` with paginated results 34 - - [x] Typeahead autocomplete via `searchActorsTypeahead` 35 - - [x] Drift migration: add `search_history` table (query, type, searched_at, account_did) 36 - - [x] Persisted search history — display recent queries, tap to re-execute, swipe to delete, cap at 50 per account 37 - - [x] Search with `@` should autocomplete with avatars + handles (debounced) 13 + Completed [2026-03-19](../../CHANGELOG.md#2026-03-19) 38 14 39 15 ## M7 — Dev Tools (PDS Explorer) 40 16 41 - - [x] `DevToolsCubit` with request/response state for stateless exploration 42 - - [x] Handle / DID input with resolution via `resolveHandle` 43 - - [x] Repository overview via `describeRepo` — list collections with record counts 44 - - [x] Collection browser via `listRecords` — paginated record list per collection 45 - - [x] Record inspector via `getRecord` — pretty-printed JSON with syntax highlighting 46 - - [x] AT-URI input — paste `at://` URI to jump directly to a record 47 - - [x] Add Dev Tools entry in Settings screen, navigable by all users 48 - - [x] Include link to <https://pds.ls> as inspiration (pdsls) 49 - - [x] Construct <https://aturi.to> links from AT-URI. 50 - - ex. `at://did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.feed.post/3m6mwoadjbp2d` becomes 51 - <https://aturi.to/did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.feed.post/3m6mwoadjbp2d> 17 + Completed [2026-03-18](../../CHANGELOG.md#2026-03-18)
+4 -42
docs/tasks/phase-3.md
··· 2 2 3 3 ## M8 — Post Composition 4 4 5 - - [x] Full-screen compose modal with text input, live grapheme counter (300 max), and submit button 6 - - [x] `ComposeBloc` — events: `TextChanged`, `MediaAttached`, `MediaRemoved`, `AltTextUpdated`, `VideoAttached`, `VideoRemoved`, `DraftSaved`, `DraftLoaded`, `PostScheduled`, `PostSubmitted` 7 - - [x] Image attachment via `uploadBlob` — up to 4 images, alt text input per image, file size (1 MB max) and MIME type (JPEG, PNG, WebP) validation 8 - - [x] Video attachment via `app.bsky.video.uploadVideo` — 1 per post (mutually exclusive with images), 100 MB max, MP4 only 9 - - [x] Video upload quota check via `getUploadLimits` before upload; show limit message if `canUpload` is false 10 - - [x] Video processing job polling via `getJobStatus` with progress indicator; handle `JOB_STATE_FAILED` with error display and retry 11 - - [x] Video embed via `app.bsky.embed.video` with alt text, aspectRatio, and optional captions 12 - - [x] Live facet detection and preview via `bluesky_text` (mentions, links, hashtags) 13 - - [x] Post creation via `com.atproto.repo.createRecord` with `app.bsky.feed.post` collection 14 - - [x] Reply support — pass `parent` + `root` refs when composing from a post thread 15 - - [x] Drift migration: add `drafts` table (id, account_did, text, reply_uri, embed_json, media_paths, created_at, updated_at, scheduled_at) 16 - - [x] Draft save on network failure, explicit save, and back-navigation 17 - - [x] Drafts list UI accessible from compose toolbar 18 - - [x] Scheduled posts — date/time picker, background task via WorkManager / BGTaskScheduler 19 - - [x] Floating action button on home screen to open compose modal 5 + Completed [2026-03-18](../../CHANGELOG.md#2026-03-18) 20 6 21 7 ## M9 — Notifications 22 8 23 - - [x] Notifications screen with grouped-by-day notification list 24 - - [x] `NotificationBloc` — events: `NotificationsRequested`, `NotificationsRefreshed`, `NotificationsPageLoaded`, `NotificationsMarkedRead` 25 - - [x] Fetch notifications via `listNotifications` with cursor pagination 26 - - [x] Render all notification reasons: like, repost, follow, mention, reply, quote 27 - - [x] Each notification row: author avatar, reason icon, summary text, optional post preview 28 - - [x] Unread count badge on nav bar via `getUnreadCount` polling (30s interval) 29 - - [x] Mark as read via `updateSeen` when notifications screen opens 30 - - [x] Tap notification to navigate to relevant post or profile 9 + Completed [2026-03-19](../../CHANGELOG.md#2026-03-19) 31 10 32 11 ## M10 — Post & Profile Actions 33 12 34 - - [x] `PostActionRepository` — like, repost, delete via `com.atproto.repo.createRecord` / `deleteRecord` 35 - - [x] `PostActionCubit` — optimistic state updates for like / repost toggle with rollback on failure 36 - - [x] Like toggle: create `app.bsky.feed.like` record or delete by rkey; update `viewer.like` and `likeCount` 37 - - [x] Repost toggle: create `app.bsky.feed.repost` record or delete by rkey; update `viewer.repost` and `repostCount` 38 - - [x] Post action bar UI — like, repost, reply, share buttons with animated state transitions 39 - - [x] `ProfileActionRepository` — follow, mute, block, report 40 - - [x] `ProfileActionCubit` — optimistic follow/mute/block state with rollback 41 - - [x] Follow toggle: create `app.bsky.graph.follow` record or delete by rkey; update `viewer.following` 42 - - [x] Mute toggle via `app.bsky.graph.muteActor` / `unmuteActor`; update `viewer.muted` 43 - - [x] Block toggle: create `app.bsky.graph.block` record or delete by rkey; update `viewer.blocking` 44 - - [x] Profile action buttons: Follow / Following / Mute / Block in profile header and overflow menu 45 - - [x] Report dialog: reason picker + optional description, submit via `com.atproto.moderation.createReport` 46 - - [x] Report for both posts (RepoStrongRef subject) and accounts (RepoRef subject) 47 - - [x] Confirmation dialog before mute / block actions 48 - - [x] Thread muting via `app.bsky.feed.threadgate` awareness (show muted-thread indicator) 13 + Completed [2026-03-17](../../CHANGELOG.md#2026-03-17) 49 14 50 15 ## M11 — Saved Posts 51 16 52 - - [x] Drift migration: add `saved_posts` table (id, account_did, post_uri, post_json, saved_at) with unique constraint on (account_did, post_uri) 53 - - [x] `SavedPostsCubit` — read/write saved posts, expose stream of saved URIs for icon state 54 - - [x] Bookmark icon on post action bar — toggle saved state 55 - - [x] Saved posts list screen accessible from profile or settings 17 + Completed [2026-03-17](../../CHANGELOG.md#2026-03-17)
+4 -51
docs/tasks/phase-4.md
··· 2 2 3 3 ## M12 — Direct Messages 4 4 5 - - [x] Conversation list screen via `chat.bsky.convo.listConvos` with pagination 6 - - [x] `ConvoListBloc` — events: `ConvosRequested`, `ConvosRefreshed`, `ConvoMuted`, `ConvoUnmuted` 7 - - [x] Primary / Requests tab filtering on conversation list 8 - - [x] Message thread screen via `chat.bsky.convo.getMessages` with pagination 9 - - [x] `MessageBloc` — events: `MessagesRequested`, `MessagesPageLoaded`, `MessageSent`, `MessageDeleted`, `ConvoMarkedRead` 10 - - [x] Chat bubble layout — current user right-aligned, others left-aligned 11 - - [x] Send messages via `chat.bsky.convo.sendMessage` 12 - - [x] New conversation via `chat.bsky.convo.getConvoForMembers` 13 - - [x] Long-press to copy individual messages, overflow menu "Copy All" for full thread 14 - - [x] Mute / unmute conversations 15 - - [x] Mark conversation as read via `chat.bsky.convo.updateRead` 5 + Completed [2026-03-19](../../CHANGELOG.md#2026-03-19) 16 6 17 7 ## M13 — Media Playback & Download 18 8 19 - - [x] Add `photo_view`, `video_player`, `chewie`, `dio`, `gal`, `permission_handler` to `pubspec.yaml` 20 - 21 - ### Images 22 - 23 - - [x] `ImageViewerScreen` — full-screen `PageView` of `PhotoView` widgets loading `fullsize` URLs with hero animation from thumbnail 24 - - [x] Page indicator for multi-image posts; alt text bar at the bottom of each page 25 - - [x] Swipe-down-to-dismiss gesture on image viewer 26 - - [x] Download button in image viewer toolbar — request permission, download via `dio` with progress indicator, save via `gal`, show snackbar result 27 - - [x] Share button in image viewer toolbar via `share_plus` 28 - - [x] Long-press context menu on image thumbnails in post cards — "Save image" and "Share" options 29 - 30 - ### Video Player 31 - 32 - - [x] `VideoPlayerScreen` — `chewie` wrapping `VideoPlayerController.networkUrl` with HLS `playlist` URL 33 - - [x] Video player uses embed `aspectRatio` when available, defaults to 16:9 34 - - [x] Video thumbnail as placeholder until player initialises; controller disposed on screen pop 35 - - [x] GIF-presentation mode — auto-play, loop, muted, controls hidden when `presentation` is `"gif"` 36 - - [x] Download button in video player toolbar — parse `.m3u8` for highest-bandwidth variant URL, download MP4 via `dio` with progress, save via `gal` 37 - - [x] Declare `NSPhotoLibraryAddUsageDescription` in `Info.plist` and storage permissions in `AndroidManifest.xml` 38 - - [x] Replace `_launchExternal` calls for image/video embeds in `PostCard` with navigation to the new viewer screens 9 + Completed [2026-03-19](../../CHANGELOG.md#2026-03-19) 39 10 40 11 ## M14 — Account Switching 41 12 ··· 59 30 60 31 ## M16 — Jump to Profile 61 32 62 - - [x] Floating action button on search screen 63 - - [x] Handle input dialog with autocomplete via `searchActorsTypeahead` 64 - - [x] Navigate to profile screen on selection or enter 65 - - [x] Update bottom navigation to include Notifications and Messages tabs (5-tab layout) 33 + Completed [2026-03-19](../../CHANGELOG.md#2026-03-19) 66 34 67 35 ## M17 — Labelers & Content Moderation 68 36 69 - - [x] Fetch user's labeler subscriptions from preferences via `app.bsky.actor.getPreferences` (`labelersPref`) 70 - - [x] Include subscribed labeler DIDs in `atproto-accept-labelers` header on all XRPC requests 71 - - [x] `ModerationService` — wraps the `bluesky` package's `moderatePost`, `moderateProfile`, `moderateNotification` functions 72 - - [x] Run moderation decisions on all displayed posts and profiles 73 - - [x] Apply `ModerationUI` results: filter, blur, alert, inform per display context (contentList, contentView, contentMedia, avatar, profileList, profileView) 74 - - [x] Blur overlay on posts/media with click-through "Show content" button 75 - - [x] Warning badges on profiles and posts for alert/inform labels 76 - - [x] Content filtering — remove posts with `filter` decisions from feed and notification lists 77 - - [x] Labeler management screen: list subscribed labelers via `app.bsky.labeler.getServices` 78 - - [x] Subscribe / unsubscribe to labelers by updating `labelersPref` via `putPreferences` 79 - - [x] Per-label preference configuration: ignore / warn / hide per label value per labeler 80 - - [x] Store label preferences as `contentLabelPref` entries via `putPreferences` 81 - - [x] Adult content toggle (requires `adultContentEnabled` preference) 82 - - [x] Self-label support — render self-labels embedded in posts and profiles 83 - - [x] Labeler detail screen: show labeler creator, policies, and custom label definitions with localised names 84 - - [x] Drift table: `labeler_cache` (labeler_did, policies_json, fetched_at) for offline label definition lookup 37 + Completed [2026-03-21](../../CHANGELOG.md#2026-03-21) 85 38 86 39 ## M18 — Lists 87 40
+6 -43
docs/tasks/ui-refactor.md
··· 2 2 3 3 ## M0 — Foundation & Layout Settings Persistence 4 4 5 - - [x] Add `ui_density` and `feed_architecture` keys to Drift `settings` table 6 - - [x] Drift migration for new settings keys 7 - - [x] Extend `SettingsCubit` / `SettingsState` with density and feed architecture fields 8 - - [x] `UiDensity` enum (`compact`, `standard`, `relaxed`) with padding scale factors 9 - - [x] `FeedArchitecture` enum (`grid`, `linear`) 10 - - [x] Theme extension or `InheritedWidget` that provides density-scaled spacing values 5 + Completed 2026-03-20 11 6 12 7 ## M1 — Navigation Chrome 13 8 14 - - [x] Custom top app bar widget replacing stock `AppBar` — hamburger, section label, avatar 15 - - [x] Home-screen variant with inline feed switcher tabs 16 - - [x] Navigation drawer with Messages and Settings entries 17 - - [x] Refactor `AppShell` bottom nav: 6 tabs → 4 (Home, Search, Alerts, Profile) 18 - - [x] Bottom nav styling: `h-80`, semi-transparent blur background, labels, filled active icon 19 - - [x] Route updates — Messages and Settings accessible via drawer instead of bottom tabs 20 - - [x] Tests for navigation (drawer opens, tabs switch, routes resolve) 9 + Completed 2026-03-20 21 10 22 11 ## M2 — Post Card Variants 23 12 24 - - [x] Refactor `PostCard` to the linear variant: square avatars, uppercase handle, bordered footer 25 - - [x] New `GridPostCard` widget — image region, content region, footer 26 - - [x] Text-only grid card variant (no image — expanded body text) 27 - - [x] Shared `PostCardFooter` widget (action icons left, timestamp right, top border) 28 - - [x] Wire both variants to `PostCardWithActions` for action state management 29 - - [x] Tests for both card variants 13 + Completed 2026-03-20 30 14 31 15 ## M3 — Home Feed Grid Layout 32 16 33 - - [x] `HomeFeedScreen` reads `feed_architecture` from `SettingsCubit` 34 - - [x] Grid mode: responsive `SliverGrid` with breakpoint-based column count 35 - - [x] Linear mode: existing `ListView` of linear post cards (with more space around cards) 36 - - [x] Feed architecture toggle triggers rebuild without re-fetch 37 - - [x] Tests for grid/linear switching and column count at breakpoints 17 + Completed 2026-03-20 38 18 39 19 ## M4 — Profile Screen Refactor 40 20 41 - - [x] Profile header: square avatar, cover image (grayscale, opacity), stats row with border 42 - - [x] Display name uppercase + tight tracking, handle below 43 - - [x] Sticky tab bar with backdrop blur and uppercase labels 44 - - [x] Large-card grid layout for profile posts in grid mode, with the metadata info card retained above the feed 45 - - [x] Linear fallback for profile posts when feed architecture is "linear" 46 - - [x] Tests for profile header rendering and layout mode switching 21 + Completed 2026-03-20 47 22 48 23 ## M5 — Layout Settings Screen 49 24 ··· 56 31 57 32 ## M6 — Collapsible Threaded Replies 58 33 59 - - [x] Recursive `ThreadReplyNode` widget that renders nested replies from `ThreadViewPost.replies` 60 - - [x] Indentation with cumulative `24px` left padding per depth level 61 - - [x] Color-coded vertical threadlines (cycle palette of 6 muted theme-derived colors) 62 - - [x] Tap-threadline-to-collapse interaction with `24dp` touch target 63 - - [x] Long-press-to-collapse as secondary affordance 64 - - [x] Collapsed state: header visible, body/children hidden, "N replies hidden" indicator 65 - - [x] `AnimatedSize` / `AnimatedCrossFade` collapse transition (`200ms`) 66 - - [x] Depth cap at 6 with "Continue this thread →" navigation link 67 - - [x] Local collapse state via `Set<String>` of post URIs in screen `State` 68 - - [x] `thread_auto_collapse_depth` setting in Drift + Drift migration 69 - - [x] Expose auto-collapse depth in Layout Settings screen 70 - - [x] Never auto-collapse OP replies 71 - - [x] Tests for thread tree rendering, collapse/expand, depth cap, and auto-collapse behavior 34 + Completed [2026-03-21](../../CHANGELOG.md#2026-03-21)