- Implemented `hydrateVideoHistoryBatch` in `NostrClient` to fetch missing root events and sparse histories in a single `pool.list` request.
- Refactored `hydrateVideoHistory` to use shared helper methods `getLocalVideoHistory` and `_processAndCacheEvent`.
- Added `resolveVideoPostedAtBatch` to `PlaybackCoordinator` which delegates to the batched client method.
- Updated `VideoListView` to collect videos needing timestamp resolution and call the batch method, falling back to individual calls if necessary.
- Added regression test `tests/performance/resolvePostedAt.test.mjs` to verify reduced network calls.
Co-authored-by: PR0M3TH3AN <[email protected]>
Extracted the complex playback logic from `js/app/playbackCoordinator.js` into a new `js/services/playbackStrategyService.js`.
This improves maintainability by separating the orchestration logic from the application glue code.
The coordinator now delegates to the service, passing a context object for UI interactions and state synchronization.
Co-authored-by: PR0M3TH3AN <[email protected]>
The user's block/mute list (NIP-51) was not being checked when
processing direct messages, allowing blocked users' messages to appear
in conversations, trigger notifications, and increment unseen counts.
This adds block filtering at four layers:
- nostrService.applyDirectMessage: drops incoming DMs from blocked users
before they enter the in-memory message cache
- nostrService.persistDirectMessageRecord: prevents blocked DM senders
from being persisted to IndexedDB or triggering notifications
- profileModalController.buildDmConversationData: filters blocked users
from the conversation list UI (catches pre-block persisted messages)
- applicationBootstrap: excludes blocked-user conversations from the
unread DM badge count
The block checker is injected via setDmBlockChecker() to keep
nostrService decoupled from userBlocks, wired up in app.js init().
https://claude.ai/code/session_01EAVLtAM14GN99Eik8otLg2
- Moved `showError`, `showStatus`, `showSuccess`, and `updateNotificationPortalVisibility` logic to `js/ui/notificationController.js`.
- Instantiated `NotificationController` in `js/ui/applicationBootstrap.js`.
- Refactored `js/app.js` to delegate notification calls to the controller.
- Added unit tests for `NotificationController`.
- Followed AGENTS.md refactoring checklist.
Co-authored-by: PR0M3TH3AN <[email protected]>
Moves `handleAddProfile` logic from the main application class into `ProfileModalController` to improve separation of concerns as per `AGENTS.md`.
- Extracts `handleAddProfile` to `js/ui/profileModalController.js`.
- Updates `ProfileModalController` to handle add account flow internally.
- Removes legacy callback wiring from `js/app.js` and `js/ui/applicationBootstrap.js`.
- Adds unit tests for the extracted logic in `tests/ui/profileModalController-addProfile.test.mjs`.
Co-authored-by: PR0M3TH3AN <[email protected]>
This change ensures the 'Explore' link is visible in the sidebar when the user is logged in, and hidden when logged out, consistent with other authenticated routes like 'For You' and 'Subscriptions'.
- Updated `js/app.js` to handle `exploreLink` visibility in `applyAuthenticatedUiState` and `applyLoggedOutUiState`.
- Initialized `exploreLink` property in `js/ui/applicationBootstrap.js`.
- Updated `tests/app/hydrate-sidebar-navigation.test.mjs` to verify the behavior.
- Added "Edit Profile" button to active profile card in profile modal
- Created `profilePaneEdit` with form fields for profile metadata (Kind 0)
- Implemented `populateEditPane`, `handleEditProfile`, `handleSaveProfile` in `ProfileModalController`
- Added file upload support for profile/banner images using `r2Service`
- Injected `r2Service` into `ProfileModalController` via `ApplicationBootstrap`
- Verified functionality with manual check of logic and structure
Removes a premature call to `initializeLoginModalController` in `ApplicationBootstrap` which was attempting to initialize the login modal before the DOM was fully hydrated, causing a "modal container not found" warning during startup. The modal is already correctly initialized later in `js/index.js` after markup loading completes.
- Add Storage tab to Profile Modal HTML with provider selector (R2 default) and connection form
- Wire ProfileModalController to handle tab switching, unlocking storage, and saving/testing connections
- Inject storageService into ProfileModalController via ApplicationBootstrap
- Repurpose Endpoint input as Account ID for R2 configurations
- Implement form validation and lock state handling