diff --git a/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitWidgetProvider.kt b/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitWidgetProvider.kt index 641b208..6a18f22 100644 --- a/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitWidgetProvider.kt +++ b/android/app/src/main/kotlin/app/cogwheel/conduit/ConduitWidgetProvider.kt @@ -57,7 +57,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_NEW_CHAT") + Uri.parse("conduit://$ACTION_NEW_CHAT") ) ) views.setOnClickPendingIntent( @@ -65,7 +65,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_NEW_CHAT") + Uri.parse("conduit://$ACTION_NEW_CHAT") ) ) views.setOnClickPendingIntent( @@ -73,7 +73,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_MIC") + Uri.parse("conduit://$ACTION_MIC") ) ) views.setOnClickPendingIntent( @@ -81,7 +81,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_CAMERA") + Uri.parse("conduit://$ACTION_CAMERA") ) ) views.setOnClickPendingIntent( @@ -89,7 +89,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_PHOTOS") + Uri.parse("conduit://$ACTION_PHOTOS") ) ) views.setOnClickPendingIntent( @@ -97,7 +97,7 @@ class ConduitWidgetProvider : AppWidgetProvider() { HomeWidgetLaunchIntent.getActivity( context, MainActivity::class.java, - Uri.parse("homewidget://$ACTION_CLIPBOARD") + Uri.parse("conduit://$ACTION_CLIPBOARD") ) ) diff --git a/ios/ConduitWidget/ConduitWidget.swift b/ios/ConduitWidget/ConduitWidget.swift index c6dd5d5..39ba8ea 100644 --- a/ios/ConduitWidget/ConduitWidget.swift +++ b/ios/ConduitWidget/ConduitWidget.swift @@ -55,7 +55,7 @@ struct ConduitWidgetEntryView: View { var body: some View { VStack(spacing: 12) { // Main "Ask Conduit" pill - ChatGPT style - Link(destination: URL(string: "homewidget://new_chat")!) { + Link(destination: URL(string: "conduit://new_chat")!) { HStack(spacing: 12) { Image("HubIcon") .renderingMode(.template) @@ -82,25 +82,25 @@ struct ConduitWidgetEntryView: View { HStack(spacing: 8) { CircularIconButton( symbol: "camera", - url: "homewidget://camera", + url: "conduit://camera", contentColor: contentColor, buttonBackground: buttonBackground ) CircularIconButton( symbol: "photo.on.rectangle.angled", - url: "homewidget://photos", + url: "conduit://photos", contentColor: contentColor, buttonBackground: buttonBackground ) CircularIconButton( symbol: "waveform", - url: "homewidget://mic", + url: "conduit://mic", contentColor: contentColor, buttonBackground: buttonBackground ) CircularIconButton( symbol: "doc.on.clipboard", - url: "homewidget://clipboard", + url: "conduit://clipboard", contentColor: contentColor, buttonBackground: buttonBackground ) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8b99741..ab7216e 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -45,6 +45,16 @@ ShareMedia-app.cogwheel.conduit + + CFBundleTypeRole + Editor + CFBundleURLName + app.cogwheel.conduit.widget + CFBundleURLSchemes + + conduit + + CFBundleVersion $(FLUTTER_BUILD_NUMBER) diff --git a/lib/core/services/home_widget_service.dart b/lib/core/services/home_widget_service.dart index 8fde1b1..6ace5d7 100644 --- a/lib/core/services/home_widget_service.dart +++ b/lib/core/services/home_widget_service.dart @@ -106,19 +106,53 @@ class HomeWidgetCoordinator extends _$HomeWidgetCoordinator { } } - /// Process initial widget action after ensuring router is ready. + /// Process initial widget action after ensuring router and auth are ready. Future _processInitialWidgetAction() async { if (_pendingWidgetAction == null) return; - // Wait for router to be attached and app to be ready + // Wait for router to be attached first for (var i = 0; i < 50; i++) { // Try for up to 5 seconds await Future.delayed(const Duration(milliseconds: 100)); - // Check if router is available if (NavigationService.currentRoute != null) { DebugLogger.log( - 'Widget: Router ready, processing pending action', + 'Widget: Router ready, waiting for authentication', + scope: 'widget', + ); + break; + } + } + + if (NavigationService.currentRoute == null) { + DebugLogger.log( + 'Widget: Timeout waiting for router, clearing pending action', + scope: 'widget', + ); + _pendingWidgetAction = null; + return; + } + + // Check if action was already processed by stream handler while waiting + if (_pendingWidgetAction == null) return; + + // Now wait for authentication to complete (up to 30 seconds for login flow) + for (var i = 0; i < 300; i++) { + await Future.delayed(const Duration(milliseconds: 100)); + + if (!ref.mounted) { + DebugLogger.log( + 'Widget: Provider disposed while waiting for auth', + scope: 'widget', + ); + _pendingWidgetAction = null; + return; + } + + final authState = ref.read(authNavigationStateProvider); + if (authState == AuthNavigationState.authenticated) { + DebugLogger.log( + 'Widget: Authenticated, processing pending action', scope: 'widget', ); final uri = _pendingWidgetAction; @@ -126,10 +160,18 @@ class HomeWidgetCoordinator extends _$HomeWidgetCoordinator { await _handleWidgetClick(uri); return; } + + // If user is on login page and not loading, they need to authenticate + // Don't clear the pending action yet - keep waiting + if (authState == AuthNavigationState.needsLogin || + authState == AuthNavigationState.error) { + // Continue waiting - user might be logging in + continue; + } } DebugLogger.log( - 'Widget: Timeout waiting for router, clearing pending action', + 'Widget: Timeout waiting for authentication, clearing pending action', scope: 'widget', ); _pendingWidgetAction = null;