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