diff --git a/app/lib/core/app_shell.dart b/app/lib/core/app_shell.dart index a89c4d8992f..bd24e762429 100644 --- a/app/lib/core/app_shell.dart +++ b/app/lib/core/app_shell.dart @@ -1,10 +1,100 @@ +import 'dart:async'; +import 'package:app_links/app_links.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; import 'package:omi/mobile/mobile_app.dart'; import 'package:omi/desktop/desktop_app.dart'; +import 'package:omi/backend/preferences.dart'; +import 'package:omi/pages/apps/app_detail/app_detail.dart'; +import 'package:omi/providers/app_provider.dart'; +import 'package:omi/providers/auth_provider.dart'; +import 'package:omi/providers/home_provider.dart'; +import 'package:omi/providers/message_provider.dart'; +import 'package:omi/providers/people_provider.dart'; +import 'package:omi/providers/usage_provider.dart'; +import 'package:omi/providers/user_provider.dart'; +import 'package:omi/services/notifications.dart'; +import 'package:omi/utils/alerts/app_snackbar.dart'; +import 'package:omi/utils/platform/platform_manager.dart'; -class AppShell extends StatelessWidget { +class AppShell extends StatefulWidget { const AppShell({super.key}); + @override + State createState() => _AppShellState(); +} + +class _AppShellState extends State { + late AppLinks _appLinks; + StreamSubscription? _linkSubscription; + + Future initDeepLinks() async { + _appLinks = AppLinks(); + + // Handle links + _linkSubscription = _appLinks.uriLinkStream.distinct().listen((uri) { + debugPrint('onAppLink: $uri'); + openAppLink(uri); + }); + } + + void openAppLink(Uri uri) async { + if (uri.pathSegments.first == 'apps') { + if (mounted) { + var app = await context.read().getAppFromId(uri.pathSegments[1]); + if (app != null) { + PlatformManager.instance.mixpanel.track('App Opened From DeepLink', properties: {'appId': app.id}); + if (mounted) { + Navigator.of(context).push(MaterialPageRoute(builder: (context) => AppDetailPage(app: app))); + } + } else { + debugPrint('App not found: ${uri.pathSegments[1]}'); + AppSnackbar.showSnackbarError('Oops! Looks like the app you are looking for is not available.'); + } + } + } else { + debugPrint('Unknown link: $uri'); + } + } + + @override + void initState() { + initDeepLinks(); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (context.read().isSignedIn()) { + context.read().setupHasSpeakerProfile(); + context.read().setupUserPrimaryLanguage(); + context.read().initialize(); + context.read().initialize(); + try { + await PlatformManager.instance.intercom.loginIdentifiedUser(SharedPreferencesUtil().uid); + } catch (e) { + debugPrint('Failed to login to Intercom: $e'); + } + + context.read().setMessagesFromCache(); + context.read().setAppsFromCache(); + context.read().refreshMessages(); + context.read().fetchSubscription(); + + NotificationService.instance.saveNotificationToken(); + } else { + if (!PlatformManager.instance.isAnalyticsSupported) { + await PlatformManager.instance.intercom.loginUnidentifiedUser(); + } + } + PlatformManager.instance.intercom.setUserAttributes(); + }); + super.initState(); + } + + @override + void dispose() { + _linkSubscription?.cancel(); + super.dispose(); + } + @override Widget build(BuildContext context) { return LayoutBuilder( @@ -13,7 +103,7 @@ class AppShell extends StatelessWidget { if (constraints.maxWidth >= 1100) { return const DesktopApp(); // Desktop app tree } else { - return const MobileApp(); // Mobile app tree (existing) + return const MobileApp(); // Mobile app tree } }, ); diff --git a/app/lib/desktop/pages/onboarding/desktop_onboarding_wrapper.dart b/app/lib/desktop/pages/onboarding/desktop_onboarding_wrapper.dart index fddec6c5d10..c47f1082f35 100644 --- a/app/lib/desktop/pages/onboarding/desktop_onboarding_wrapper.dart +++ b/app/lib/desktop/pages/onboarding/desktop_onboarding_wrapper.dart @@ -140,7 +140,9 @@ class _DesktopOnboardingWrapperState extends State wit SharedPreferencesUtil().hasOmiDevice = true; SharedPreferencesUtil().verifiedPersonaId = null; MixpanelManager().onboardingStepCompleted('Auth'); + if(context.mounted) { context.read().setupHasSpeakerProfile(); + } IntercomManager.instance.loginIdentifiedUser(SharedPreferencesUtil().uid); IntercomManager.instance.updateUser( FirebaseAuth.instance.currentUser!.email, diff --git a/app/lib/main.dart b/app/lib/main.dart index 38e80939519..6207e38cb1b 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:app_links/app_links.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; @@ -16,13 +15,8 @@ import 'package:omi/env/prod_env.dart'; import 'package:omi/firebase_options_dev.dart' as dev; import 'package:omi/firebase_options_prod.dart' as prod; import 'package:omi/flavors.dart'; -import 'package:omi/pages/apps/app_detail/app_detail.dart'; import 'package:omi/pages/apps/providers/add_app_provider.dart'; -import 'package:omi/pages/home/page.dart'; import 'package:omi/pages/conversation_detail/conversation_detail_provider.dart'; -import 'package:omi/pages/onboarding/device_selection.dart'; -import 'package:omi/pages/onboarding/wrapper.dart'; -import 'package:omi/pages/persona/persona_profile.dart'; import 'package:omi/core/app_shell.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/providers/app_provider.dart'; @@ -325,100 +319,7 @@ class _MyAppState extends State with WidgetsBindingObserver { } } -class DeciderWidget extends StatefulWidget { - const DeciderWidget({super.key}); - @override - State createState() => _DeciderWidgetState(); -} - -class _DeciderWidgetState extends State { - late AppLinks _appLinks; - StreamSubscription? _linkSubscription; - - Future initDeepLinks() async { - _appLinks = AppLinks(); - - // Handle links - _linkSubscription = _appLinks.uriLinkStream.distinct().listen((uri) { - debugPrint('onAppLink: $uri'); - openAppLink(uri); - }); - } - - void openAppLink(Uri uri) async { - if (uri.pathSegments.first == 'apps') { - if (mounted) { - var app = await context.read().getAppFromId(uri.pathSegments[1]); - if (app != null) { - PlatformManager.instance.mixpanel.track('App Opened From DeepLink', properties: {'appId': app.id}); - if (mounted) { - Navigator.of(context).push(MaterialPageRoute(builder: (context) => AppDetailPage(app: app))); - } - } else { - debugPrint('App not found: ${uri.pathSegments[1]}'); - AppSnackbar.showSnackbarError('Oops! Looks like the app you are looking for is not available.'); - } - } - } else { - debugPrint('Unknown link: $uri'); - } - } - - @override - void initState() { - initDeepLinks(); - - WidgetsBinding.instance.addPostFrameCallback((_) async { - - if (context.read().isSignedIn()) { - context.read().setupHasSpeakerProfile(); - context.read().setupUserPrimaryLanguage(); - context.read().initialize(); - context.read().initialize(); - try { - await PlatformManager.instance.intercom.loginIdentifiedUser(SharedPreferencesUtil().uid); - } catch (e) { - debugPrint('Failed to login to Intercom: $e'); - } - - context.read().setMessagesFromCache(); - context.read().setAppsFromCache(); - context.read().refreshMessages(); - context.read().fetchSubscription(); - - NotificationService.instance.saveNotificationToken(); - } else { - if (!PlatformManager.instance.isAnalyticsSupported) { - await PlatformManager.instance.intercom.loginUnidentifiedUser(); - } - } - PlatformManager.instance.intercom.setUserAttributes(); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Consumer( - builder: (context, authProvider, child) { - if (authProvider.isSignedIn()) { - if (SharedPreferencesUtil().onboardingCompleted) { - return const HomePageWrapper(); - } else { - return const OnboardingWrapper(); - } - } else if (SharedPreferencesUtil().hasOmiDevice == false && - SharedPreferencesUtil().hasPersonaCreated && - SharedPreferencesUtil().verifiedPersonaId != null) { - return const PersonaProfilePage(); - } else { - return const DeviceSelectionPage(); - } - }, - ); - } -} class CustomErrorWidget extends StatelessWidget { final String errorMessage; diff --git a/app/lib/pages/persona/persona_profile.dart b/app/lib/pages/persona/persona_profile.dart index 74231d11873..f05354c558d 100644 --- a/app/lib/pages/persona/persona_profile.dart +++ b/app/lib/pages/persona/persona_profile.dart @@ -4,8 +4,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:omi/backend/auth.dart'; import 'package:omi/backend/preferences.dart'; import 'package:omi/backend/schema/app.dart'; +import 'package:omi/core/app_shell.dart'; import 'package:omi/gen/assets.gen.dart'; -import 'package:omi/main.dart'; import 'package:omi/pages/onboarding/wrapper.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/providers/auth_provider.dart'; @@ -560,7 +560,7 @@ class _PersonaProfilePageState extends State { Provider.of(context, listen: false).setRouting(PersonaProfileRouting.no_device); await signOut(); Navigator.of(context).pop(); - routeToPage(context, const DeciderWidget(), replace: true); + routeToPage(context, const AppShell(), replace: true); }, child: const Text('Sign Out', style: TextStyle(color: Colors.redAccent)), ), diff --git a/app/lib/pages/settings/delete_account.dart b/app/lib/pages/settings/delete_account.dart index 6f845eee5bd..f2cb8b368bd 100644 --- a/app/lib/pages/settings/delete_account.dart +++ b/app/lib/pages/settings/delete_account.dart @@ -2,7 +2,7 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:omi/backend/http/api/users.dart'; import 'package:omi/backend/preferences.dart'; -import 'package:omi/main.dart'; +import 'package:omi/core/app_shell.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:omi/widgets/dialog.dart'; @@ -37,7 +37,7 @@ class _DeleteAccountState extends State { setState(() { isDeleteing = false; }); - routeToPage(context, const DeciderWidget(), replace: true); + routeToPage(context, const AppShell(), replace: true); } @override diff --git a/app/lib/pages/settings/page.dart b/app/lib/pages/settings/page.dart index d86f1710cfc..aee3358f4ba 100644 --- a/app/lib/pages/settings/page.dart +++ b/app/lib/pages/settings/page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:omi/backend/auth.dart'; import 'package:omi/backend/preferences.dart'; -import 'package:omi/main.dart'; +import 'package:omi/core/app_shell.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/pages/settings/about.dart'; import 'package:omi/pages/settings/data_privacy_page.dart'; @@ -166,7 +166,7 @@ class _SettingsPageState extends State { Provider.of(context, listen: false).setRouting(PersonaProfileRouting.no_device); await signOut(); Navigator.of(context).pop(); - routeToPage(context, const DeciderWidget(), replace: true); + routeToPage(context, const AppShell(), replace: true); }, "Sign Out?", "Are you sure you want to sign out?"); }, ); @@ -219,7 +219,7 @@ class _SettingsPageState extends State { Provider.of(context, listen: false).setRouting(PersonaProfileRouting.no_device); await signOut(); Navigator.of(context).pop(); - routeToPage(context, const DeciderWidget(), replace: true); + routeToPage(context, const AppShell(), replace: true); }, "Sign Out?", "Are you sure you want to sign out?"); }, ); diff --git a/app/lib/pages/settings/settings_drawer.dart b/app/lib/pages/settings/settings_drawer.dart index f752d9bc35d..2d5f6ba231c 100644 --- a/app/lib/pages/settings/settings_drawer.dart +++ b/app/lib/pages/settings/settings_drawer.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:omi/backend/auth.dart'; import 'package:omi/backend/preferences.dart'; -import 'package:omi/main.dart'; +import 'package:omi/core/app_shell.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/pages/settings/about.dart'; import 'package:omi/pages/settings/data_privacy_page.dart'; @@ -291,9 +291,9 @@ class _SettingsDrawerState extends State { await SharedPreferencesUtil().clearUserPreferences(); personaProvider.setRouting(PersonaProfileRouting.no_device); await signOut(); - if (context.mounted) { - routeToPage(context, const DeciderWidget(), replace: true); - } + if (context.mounted){ + routeToPage(context, const AppShell(), replace: true); + } }, "Sign Out?", "Are you sure you want to sign out?", @@ -365,7 +365,7 @@ class _SettingsDrawerState extends State { personaProvider.setRouting(PersonaProfileRouting.no_device); await signOut(); if (context.mounted) { - routeToPage(context, const DeciderWidget(), replace: true); + routeToPage(context, const AppShell(), replace: true); } }, "Sign Out?",