perf(app): reduce startup work — remove macOS calendar + defer providers#6597
perf(app): reduce startup work — remove macOS calendar + defer providers#6597
Conversation
The EventKit-based calendar feature was macOS-only and the macOS Flutter desktop app has been removed.
EventKit bridge for the removed macOS desktop app.
No remaining navigation entry points after macOS desktop removal.
Only the removed macOS calendar provider called this endpoint. Backend /calendar/meetings router is kept intact for future use.
Only referenced by the removed calendar_meetings HTTP client.
Drops calendarId, calendarType, calendarIntegrationEnabled, showEventsWithNoParticipants, showMeetingsInMenuBar, and enabledCalendarIds — all exclusive to the removed EventKit flow.
…vider The field was declared but never read or assigned anywhere.
Declared but never invoked.
…ettings page Both providers are only consumed by the developer settings flow. Moving them out of the root MultiProvider avoids eager construction and API work on app launch for users who never open developer settings.
Single-page provider; no reason to create it at app launch.
Only consumed by the chat page and its voice recorder widget. checkPendingRecording() (disk I/O) now fires on chat page mount instead of on every cold start.
Scoped to the payments flow so the provider is not constructed at app launch for users who never visit payments.
…AddAppPage After publishing a paid app, the page does a single getPaymentMethodsStatus() + activeMethod read to decide whether to show the "start earning" prompt. A local instance avoids needing the provider in the widget tree and allows the root registration to be removed.
- Remove CalendarProvider wiring (macOS-only, now deleted). - Remove 5 providers now scoped to their consuming pages: DeveloperModeProvider, McpProvider, AiAppGeneratorProvider, VoiceRecorderProvider, PaymentMethodProvider. - Mark 6 providers lazy so they construct on first read instead of app launch: ActionItemsProvider, GoalsProvider, TaskIntegrationProvider, IntegrationProvider, FolderProvider, PhoneCallProvider. Net effect: cold-start MultiProvider drops from ~25 eager providers to ~14, and removes startup side-effects including GoalsProvider.init() API fetch, VoiceRecorderProvider disk scan, and DeveloperModeProvider.initialize().
|
@greptile-apps review |
Greptile SummaryThis PR does two things: removes ~900 lines of dead macOS-only EventKit calendar code (provider, service, settings page, API client, schema, 6 preference keys), and reduces cold-start work by moving 4 providers to screen scope and marking 8 root providers All provider migrations were verified to be safe: Confidence Score: 5/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph Root["Root MultiProvider (app startup)"]
direction TB
E1[AuthProvider]
E2[AppProvider]
E3[CaptureProvider]
E4[ConversationProvider]
E5[DeviceProvider]
E6[UserProvider]
E7[SyncProvider]
E8[LocaleProvider]
E9[AnnouncementProvider]
E10[MemoriesProvider]
L1["ActionItemsProvider 🔵 lazy"]
L2["GoalsProvider 🔵 lazy"]
L3["TaskIntegrationProvider 🔵 lazy"]
L4["IntegrationProvider 🔵 lazy"]
L5["FolderProvider 🔵 lazy"]
L6["McpProvider 🔵 lazy"]
L7["PaymentMethodProvider 🔵 lazy"]
L8["PhoneCallProvider 🔵 lazy"]
end
subgraph Removed["Removed from Root ❌"]
R1[CalendarProvider]
R2[DeveloperModeProvider]
R3[AiAppGeneratorProvider]
R4[VoiceRecorderProvider]
R5[PaymentMethodProvider eager]
end
subgraph Screens["Screen-Scoped Providers"]
S1["DeveloperSettingsPage\n→ DeveloperModeProvider()..initialize()"]
S2["AiAppGeneratorPage\n→ AiAppGeneratorProvider()"]
S3["ChatPage\n→ VoiceRecorderProvider()..checkPendingRecording()"]
S4["AddAppPage\n→ PaymentMethodProvider() local one-shot"]
end
Root --> S1
Root --> S2
Root --> S3
Root --> S4
style Removed fill:#ff6b6b,color:#fff
style L1 fill:#4ecdc4,color:#fff
style L2 fill:#4ecdc4,color:#fff
style L3 fill:#4ecdc4,color:#fff
style L4 fill:#4ecdc4,color:#fff
style L5 fill:#4ecdc4,color:#fff
style L6 fill:#4ecdc4,color:#fff
style L7 fill:#4ecdc4,color:#fff
style L8 fill:#4ecdc4,color:#fff
Reviews (2): Last reviewed commit: "fix(app): restore McpProvider and Paymen..." | Re-trigger Greptile |
| return ChangeNotifierProvider( | ||
| create: (_) => PaymentMethodProvider(), | ||
| child: const _PaymentsPageView(), | ||
| ); |
There was a problem hiding this comment.
Provider scope breaks
StripeConnectSetup and PaypalSetupPage
PaymentMethodProvider is now scoped inside PaymentsPage's widget tree. When routeToPage(context, const StripeConnectSetup()) or routeToPage(context, const PaypalSetupPage()) is called from _PaymentsPageView, those pages are pushed as new Navigator routes. A Navigator-pushed route's BuildContext is sourced from the Navigator's overlay — it is not a child of PaymentsPage's ChangeNotifierProvider. Both StripeConnectSetup.initState (context.read<PaymentMethodProvider>().getSupportedCountries()) and PaypalSetupPage.initState (context.read<PaymentMethodProvider>()) will throw ProviderNotFoundException at runtime and crash the app.
Fix: keep PaymentMethodProvider at the root MultiProvider, or wrap each navigated-to page with a ChangeNotifierProvider.value passing the existing instance before routing.
showDialog pushes CreateMcpApiKeyDialog onto the root Navigator, so the dialog's BuildContext is a sibling of the page, not a descendant. InheritedProvider is not captured by dialog routes, so a page-scoped McpProvider would throw ProviderNotFoundException when the dialog tries to read it. Keep DeveloperModeProvider scoped (only consumed by the page itself); McpProvider moves back to root (see main.dart).
StripeConnectSetup and PaypalSetupPage are pushed via Navigator.push, so they mount as siblings in the Navigator overlay, not children of PaymentsPage. A page-scoped provider would throw ProviderNotFoundException in their initState. Revert PaymentsPage to StatefulWidget; the provider is reinstated at root (see main.dart). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both were previously scoped to their pages, but consumers live on separate Navigator routes (a dialog and pushed setup pages) that cannot see page-scoped providers. Restoring them at root with lazy: true keeps cold-start cost zero — they still only construct on first read.
|
@greptile-apps re-review |
Summary
Two related cleanups to reduce cold-start work in the Flutter app.
1. Remove macOS-only calendar frontend code (8 commits)
The EventKit-based calendar feature was macOS-only; the macOS Flutter desktop app has been removed, so all calendar client code on mobile was dead.
CalendarProvider._init()was already a no-op stub, but the rest of the class was still wired up and instantiated eagerly at app launch.Removed:
providers/calendar_provider.dartservices/calendar_service.dartpages/settings/calendar_settings_page.dart(orphaned — no nav entry)backend/http/api/calendar_meetings.dartbackend/schema/calendar_meeting_context.dartCalendarProvider?field onCaptureProvidercalendarTypeChangedmixpanel eventPreserved: Google Calendar OAuth integration (separate
BaseIntegrationService) and the backend/calendar/meetingsrouter (kept intact for future use).2. Scope + defer non-critical providers at startup (6 commits)
Root
MultiProviderwas eagerly instantiating ~25 providers. Rescoped based on actual usage:Moved to screen scope (only one subtree consumes them):
DeveloperModeProvider+McpProvider→DeveloperSettingsPageAiAppGeneratorProvider→AiAppGeneratorPageVoiceRecorderProvider→ChatPage(disk I/OcheckPendingRecording()now fires on chat mount instead of app launch)PaymentMethodProvider→PaymentsPage;AddAppPageuses a local instance for its one-shot checkMarked
lazy: trueat root (cross-screen but no init side-effects):ActionItemsProvider,GoalsProvider,TaskIntegrationProvider,IntegrationProvider,FolderProvider,PhoneCallProviderNet cold-start impact
GoalsProvider.init()API fetch,VoiceRecorderProviderdisk scan,DeveloperModeProvider.initialize().ActionItemsProviderstill preloads 100 action items in its constructor — left as a separate follow-up (requires gating on a tasks-enabled preference).Test plan