- Add updateStarredPlans call in configureNativeFetcher to store starred
plan IDs in SharedPreferences for the native fetcher to use
- Clear starred plans if none provided to ensure state consistency
- Add starredPlansCount to configuration log for debugging
This fixes the issue where the native fetcher was querying the API
with an empty planIds array because starred plans weren't being stored
in SharedPreferences. Now when configureNativeFetcher is called with
starredPlanHandleIds, they are properly stored and available for
background prefetch operations.
Also updates package-lock.json for daily-notification-plugin v1.0.11.
- Add notification channel creation in TimeSafariApplication for Android 8.0+
Required for daily notifications to display properly. Channel ID matches
plugin's 'timesafari.daily' channel.
- Convert localhost to 10.0.2.2 in CapacitorPlatformService for Android emulators
Android emulators cannot reach localhost - they need 10.0.2.2 to access
the host machine's API server.
- Refresh native fetcher configuration when API server changes in AccountViewView
Ensures background notification prefetch uses the updated endpoint when
user changes API server URL in settings.
- Add directive for fixing notification dismiss cancellation in plugin
Documents the fix needed in plugin source to cancel notification from
NotificationManager when dismiss button is clicked.
These changes ensure daily notifications work correctly on Android, including
proper channel setup, emulator network connectivity, and configuration refresh.
Add comprehensive instrumentation to diagnose why native fetcher
is not being called during prefetch operations.
Instrumentation Added:
- TimeSafariApplication: Log app initialization, fetcher registration,
and verification with process ID and timestamps
- TimeSafariNativeFetcher: Log configuration, fetch start, source
resolution (native vs fallback), and write completion
- Diagnostic script: Filter logcat for prefetch-related events
- Investigation summary: Document root cause hypotheses and
diagnostic checklist
Log Tags:
- APP|ON_CREATE: App initialization timing and process info
- FETCHER|REGISTER_START/REGISTERED: Fetcher registration lifecycle
- FETCHER|CONFIGURE_START/CONFIGURE_COMPLETE: Configuration tracking
- PREFETCH|START/SOURCE/WRITE_OK: Prefetch operation tracking
- DISPLAY|START/LOOKUP: Display worker tracking (future)
- STORAGE|POST_PREFETCH/PRE_DISPLAY: Storage verification (future)
This instrumentation will help diagnose:
1. Registration timing issues (worker before onCreate)
2. Fetcher resolution failures (null fetcher)
3. Process mismatches (multi-process issues)
4. ID schema inconsistencies (prefetch vs display)
5. Storage persistence issues (content not saved)
Author: Matthew Raymer
Implement Android host-side integration for daily notification plugin
by creating custom Application class and native content fetcher.
Changes:
- Add TimeSafariApplication.java: Custom Application class that registers
NativeNotificationContentFetcher with the plugin on app startup
- Add TimeSafariNativeFetcher.java: Implementation of NativeNotificationContentFetcher
interface that fetches notification content from endorser API endpoint
(/api/v2/report/plansLastUpdatedBetween) using JWT authentication
- Update AndroidManifest.xml: Declare TimeSafariApplication as the custom
Application class using android:name attribute
- Add Gson dependency: Include com.google.code.gson:gson:2.10.1 in build.gradle
for JSON parsing in the native fetcher
This setup mirrors the test app configuration and enables the plugin's
background content prefetching feature. The native fetcher will be called
by the plugin 5 minutes before scheduled notification times to prefetch
content for display.
Author: Matthew Raymer
- Change from dynamic to static imports for @timesafari/daily-notification-plugin
- Remove plugin from external dependencies in vite.config.capacitor.mts to ensure proper bundling
- Add debug logging to DailyNotificationSection for troubleshooting
- Update package-lock.json with latest dependencies
Handle "Connection already exists" error when initializing SQLite database
on Capacitor platforms. The native connection can persist across app
restarts while the JavaScript connection Map is empty, causing a mismatch.
When createConnection fails with "already exists":
- Check if connection exists in JavaScript Map and retrieve it if present
- If not in Map, close the native connection and recreate to sync both sides
- Handle "already open" errors gracefully when opening existing connections
This fixes the issue where clicking "Backup Identifier Seed" would redirect
to StartView instead of SeedBackupView due to database initialization
failures in the router navigation guard.
Fixes navigation issue on both iOS and Android platforms.
- Add notification methods to PlatformService interface
- Implement notification support in CapacitorPlatformService with plugin integration
- Add stub implementations in WebPlatformService and ElectronPlatformService
- Add nativeNotificationTime, nativeNotificationTitle, and nativeNotificationMessage fields to Settings interface
- Create DailyNotificationSection component for AccountViewView integration
- Add Android manifest permissions (POST_NOTIFICATIONS, SCHEDULE_EXACT_ALARM, RECEIVE_BOOT_COMPLETED)
- Register daily-notification-plugin in capacitor.plugins.json
- Integrate DailyNotificationSection into AccountViewView
Features:
- Platform capability detection (hides on unsupported platforms)
- Permission request flow with fallback to settings
- Schedule/cancel notifications
- Time editing with HTML5 time input
- Settings persistence
- Plugin state synchronization on app load
NOTE: Currently storing notification schedule in SQLite database, but plugin
was designed to store schedule internally. Consider migrating to plugin's
internal storage to avoid database initialization issues.
Migration 006 was failing during database initialization because the SQLite
plugin splits SQL statements on semicolons, and inline comments after
semicolons were being treated as separate statements. When the last statement
was comment-only (e.g., '-- Notification body text'), it caused an error.
Fixed by removing all inline comments from the migration SQL. The comments
are already documented in the TypeScript code, so they're not needed in the
SQL itself.
NOTE: We're experiencing database initialization problems with storing
notification schedule data. The daily notification plugin was originally
designed to store the schedule internally, which would be a better approach
than storing it in our SQLite database. We should consider migrating to
using the plugin's internal storage instead of adding these columns to the
settings table.
- Update initialization to sync with plugin state on mount (checks for pre-existing schedules)
- Add updateNotificationTime() method to update schedule when time changes (cancel old, schedule new)
- Extract DailyNotificationSection into dedicated component using vue-facing-decorator
- Update component architecture to show DailyNotificationSection.vue structure
- Update Phase 2 tasks to reflect component creation and AccountViewView integration
- Add acceptance criteria for plugin state sync and time update functionality
- Update verification checklist with new requirements
- Add checkboxes to Phase 1, 2, 3 task sub-items
- Add checkboxes to Milestone success criteria
- Add checkboxes to Testing Strategy test items
- Add checkboxes to Risk Mitigation mitigation items
- Add checkboxes to Next Steps
- All actionable items now have checkboxes for tracking progress
- Consolidate AccountViewView integration strategy into unified plan
- Add comprehensive AccountViewView Integration Strategy section
- Include UI component design, data flow, and implementation decisions
- Remove separate strategy document to follow meta_feature_planning structure
- Update Phase 2 to include AccountViewView integration tasks
Consolidate organizerAdmitAndAddWithVisibility() and
memberAddContactWithVisibility() into a single unified method
processSelectedMembers() that handles both organizer and member
modes based on the isOrganizer prop.
- Remove redundant handleMainAction() wrapper method
- Update template to call processSelectedMembers directly
- Reduce code duplication by ~30% (140 lines → 98 lines)
- Maintain identical functionality for both modes
This simplifies the component structure and makes the processing
logic easier to maintain.
Remove dialogType prop and consolidate to use only isOrganizer prop.
- Remove dialogType prop from BulkMembersDialog component
- Replace all dialogType checks with isOrganizer boolean checks
- Add comments clarifying isOrganizer true/false meanings
- Remove dialog-type prop binding from MembersList component
This simplifies the component API while maintaining the same functionality.
Add infinite scroll functionality to EntityGrid component using VueUse's
useInfiniteScroll composable to handle large volumes of entities efficiently.
Changes:
- Integrate @vueuse/core useInfiniteScroll composable
- Add infinite scroll state management (displayedCount, reset function)
- Configure initial batch size (20 items) and increment size (20 items)
- Update displayedEntities, alphabeticalContacts to support progressive loading
- Add canLoadMore() logic for people, projects, and search modes
- Reset scroll state when search term or entities prop changes
- Remove maxItems prop (replaced by infinite scroll)
- Simplify displayEntitiesFunction signature (removed maxItems parameter)
- Update EntitySelectionStep and test files to remove max-items prop
Technical details:
- Uses template ref (scrollContainer) to access scrollable container
- Recent contacts (3) count toward initial batch for people grid
- Special entities (You, Unnamed) always displayed, don't count toward limits
- Infinite scroll works for both entity types and search results
- Constants are configurable at top of component (INITIAL_BATCH_SIZE, INCREMENT_SIZE)
This improves performance and UX when displaying large lists of contacts or
projects by loading content progressively as users scroll.
When displaying contacts (not search results), show the 3 most recently
added contacts at the top with a "Recently Added" heading, followed by
the rest sorted alphabetically with an "Everyone Else" heading.
- Add recentContacts and alphabeticalContacts computed properties
- Hide "You" and "Unnamed" special entities during search
- Only show search spinner when actively searching with a term
- Style section headings with uppercase, improved spacing, and borders
Add contextual feedback message when a search term is entered but no matching entities are found. The message dynamically adjusts its wording based on whether searching for people or projects.
- Add search-as-you-type functionality with 500ms debounce
- Implement search across contact names and DIDs, project names and handleIds
- Add loading spinner and dynamic clear button
- Add $contactsByDateAdded() method to PlatformServiceMixin for newest-first sorting
- Update GiftedDialog to use date-based contact ordering
- Maintain backward compatibility with existing $contacts() alphabetical sorting
- Add proper cleanup for search timeouts on component unmount
The search feature provides real-time filtering with visual feedback,
while the new sorting ensures recently added contacts appear first.
- Remove ShowAllCard component and all related functionality
- Remove showAllRoute, showAllQueryParams, and hideShowAll props
- Remove shouldShowAll computed property from EntityGrid
- Clean up ShowAll-related code from EntitySelectionStep and GiftedDialog
- Delete ShowAllCard.vue component file
- Update component documentation to reflect removal
This simplifies the entity selection interface by removing the navigation
card that allowed users to view all entities in a separate view.
- Replace individual text props with single isOrganizer boolean prop
- Add computed properties for title, description, buttonText, and emptyStateText
- Simplify parent component interface by removing text prop passing
- Update quote style from single to double quotes for consistency
- Improve component encapsulation and maintainability