diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 8710ee3..8bb1d49 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -9,9 +9,13 @@ PODS: - GoogleUtilities/Environment (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0) - PromisesObjC (~> 2.4) + - connectivity_plus (0.0.1): + - Flutter - CwlCatchException (2.2.1): - CwlCatchExceptionSupport (~> 2.2.1) - CwlCatchExceptionSupport (2.2.1) + - device_info_plus (0.0.1): + - Flutter - emoji_picker_flutter (0.0.1): - Flutter - FBAEMKit (18.0.2): @@ -22,11 +26,20 @@ PODS: - FBSDKCoreKit_Basics (18.0.2) - FBSDKLoginKit (18.0.2): - FBSDKCoreKit (= 18.0.2) + - Firebase/Analytics (11.15.0): + - Firebase/Core + - Firebase/Core (11.15.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 11.15.0) - Firebase/CoreOnly (11.15.0): - FirebaseCore (~> 11.15.0) - Firebase/Messaging (11.15.0): - Firebase/CoreOnly - FirebaseMessaging (~> 11.15.0) + - firebase_analytics (11.6.0): + - Firebase/Analytics (= 11.15.0) + - firebase_core + - Flutter - firebase_core (3.15.2): - Firebase/CoreOnly (= 11.15.0) - Flutter @@ -34,6 +47,24 @@ PODS: - Firebase/Messaging (= 11.15.0) - firebase_core - Flutter + - FirebaseAnalytics (11.15.0): + - FirebaseAnalytics/Default (= 11.15.0) + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - FirebaseAnalytics/Default (11.15.0): + - FirebaseCore (~> 11.15.0) + - FirebaseInstallations (~> 11.0) + - GoogleAppMeasurement/Default (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - FirebaseCore (11.15.0): - FirebaseCoreInternal (~> 11.15.0) - GoogleUtilities/Environment (~> 8.1) @@ -68,6 +99,32 @@ PODS: - FlutterMacOS - GoogleSignIn (~> 8.0) - GTMSessionFetcher (>= 3.4.0) + - GoogleAdsOnDeviceConversion (2.1.0): + - GoogleUtilities/Logger (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Core (11.15.0): + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/Default (11.15.0): + - GoogleAdsOnDeviceConversion (= 2.1.0) + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleAppMeasurement/IdentitySupport (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) + - GoogleAppMeasurement/IdentitySupport (11.15.0): + - GoogleAppMeasurement/Core (= 11.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 8.1) + - GoogleUtilities/MethodSwizzler (~> 8.1) + - GoogleUtilities/Network (~> 8.1) + - "GoogleUtilities/NSData+zlib (~> 8.1)" + - nanopb (~> 3.30910.0) - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) @@ -86,6 +143,9 @@ PODS: - GoogleUtilities/Logger (8.1.0): - GoogleUtilities/Environment - GoogleUtilities/Privacy + - GoogleUtilities/MethodSwizzler (8.1.0): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy - GoogleUtilities/Network (8.1.0): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" @@ -110,6 +170,8 @@ PODS: - GTMSessionFetcher/Core - image_picker_ios (0.0.1): - Flutter + - memory_info (0.0.1): + - Flutter - nanopb (3.30910.0): - nanopb/decode (= 3.30910.0) - nanopb/encode (= 3.30910.0) @@ -138,7 +200,10 @@ PODS: - FlutterMacOS DEPENDENCIES: + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`) + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) @@ -147,6 +212,7 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - memory_info (from `.symlinks/plugins/memory_info/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) @@ -166,10 +232,13 @@ SPEC REPOS: - FBSDKCoreKit_Basics - FBSDKLoginKit - Firebase + - FirebaseAnalytics - FirebaseCore - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging + - GoogleAdsOnDeviceConversion + - GoogleAppMeasurement - GoogleDataTransport - GoogleSignIn - GoogleUtilities @@ -179,8 +248,14 @@ SPEC REPOS: - PromisesObjC EXTERNAL SOURCES: + connectivity_plus: + :path: ".symlinks/plugins/connectivity_plus/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" emoji_picker_flutter: :path: ".symlinks/plugins/emoji_picker_flutter/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" firebase_core: :path: ".symlinks/plugins/firebase_core/ios" firebase_messaging: @@ -197,6 +272,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/google_sign_in_ios/darwin" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + memory_info: + :path: ".symlinks/plugins/memory_info/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: @@ -215,16 +292,20 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f + connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d CwlCatchException: 7acc161b299a6de7f0a46a6ed741eae2c8b4d75a CwlCatchExceptionSupport: 54ccab8d8c78907b57f99717fb19d4cc3bce02dc + device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 emoji_picker_flutter: 8e50ec5caac456a23a78637e02c6293ea0ac8771 FBAEMKit: 56a4f5a9607957b547b6458b17a98c5bb2736367 FBSDKCoreKit: 54f1240567e16862ab71c53c33dc347db5c524c5 FBSDKCoreKit_Basics: eb530cd6a79030dbb11df460aafb2767bcad9028 FBSDKLoginKit: 6a70798793e499335a98fab1a758d7da34af196e Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e + firebase_analytics: bf93e20703c95030404d6ddbb1adf05bf5c3885b firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7 + FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 @@ -234,12 +315,15 @@ SPEC CHECKSUMS: flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9 flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 google_sign_in_ios: 7411fab6948df90490dc4620ecbcabdc3ca04017 + GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 + GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b + memory_info: 18a37c81d0c57151f6661fd007b05f8894427a0a nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 diff --git a/lib/features/agents/presentation/screens/agent_home_screen.dart b/lib/features/agents/presentation/screens/agent_home_screen.dart index 60b9cf6..864051e 100644 --- a/lib/features/agents/presentation/screens/agent_home_screen.dart +++ b/lib/features/agents/presentation/screens/agent_home_screen.dart @@ -1336,8 +1336,10 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> { color: const Color(0xFFE6E6E6), padding: const EdgeInsets.symmetric(vertical: 24), child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Text('Specialization', + textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Fractul', fontSize: 20, @@ -1345,6 +1347,7 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> { color: AppColors.primaryDark)), const SizedBox(height: 4), const Text('Area Of Expertise and Focus', + textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Fractul', fontSize: 14, @@ -1365,8 +1368,7 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> { final hasMore = card.values.length > 3; return Container( - margin: const EdgeInsets.symmetric(horizontal: 66, vertical: 8), - width: 298, + margin: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), decoration: BoxDecoration( color: Colors.white, @@ -1375,11 +1377,13 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> { ), child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, children: [ const Icon(Icons.category_outlined, size: 28, color: AppColors.accentOrange), const SizedBox(height: 10), Text(displayName, + textAlign: TextAlign.center, style: const TextStyle( fontFamily: 'Fractul', fontSize: 14, diff --git a/lib/features/agents/presentation/screens/agent_search_screen.dart b/lib/features/agents/presentation/screens/agent_search_screen.dart index 88f94ed..503efee 100644 --- a/lib/features/agents/presentation/screens/agent_search_screen.dart +++ b/lib/features/agents/presentation/screens/agent_search_screen.dart @@ -170,7 +170,7 @@ class _AgentSearchScreenState extends ConsumerState { color: AppColors.primaryDark, ), decoration: InputDecoration( - hintText: 'Search Agents', + hintText: 'Search Professionals', hintStyle: TextStyle( fontFamily: 'Fractul', fontSize: 14, diff --git a/lib/features/auth/presentation/screens/login_screen.dart b/lib/features/auth/presentation/screens/login_screen.dart index f65e6b5..ea8d2f7 100644 --- a/lib/features/auth/presentation/screens/login_screen.dart +++ b/lib/features/auth/presentation/screens/login_screen.dart @@ -65,7 +65,10 @@ class _LoginScreenState extends ConsumerState { // Navigate on auth state changes ref.listen(authProvider, (previous, next) { if (next.status == AuthStatus.authenticated) { - context.go('/home'); + // Agents land on /profile (defaults to "Edit Profile" tab — + // their dashboard/home view). Users land on /home. + final isAgent = next.user?.role == 'AGENT'; + context.go(isAgent ? '/profile' : '/home'); } // Navigate to 2FA verification screen if (next.requiresTwoFactor && next.tempToken != null) { diff --git a/lib/features/auth/presentation/screens/verify_2fa_screen.dart b/lib/features/auth/presentation/screens/verify_2fa_screen.dart index 8c19c9b..b59e3ed 100644 --- a/lib/features/auth/presentation/screens/verify_2fa_screen.dart +++ b/lib/features/auth/presentation/screens/verify_2fa_screen.dart @@ -95,10 +95,12 @@ class _Verify2faScreenState extends ConsumerState { final authState = ref.watch(authProvider); final isLoading = authState.status == AuthStatus.loading; - // Navigate to home when authentication succeeds, reset submit lock on error + // Navigate when authentication succeeds, reset submit lock on error. + // Agents land on /profile (Edit Profile tab — their home/dashboard view). ref.listen(authProvider, (previous, next) { if (next.status == AuthStatus.authenticated) { - context.go('/home'); + final isAgent = next.user?.role == 'AGENT'; + context.go(isAgent ? '/profile' : '/home'); } if (next.status != AuthStatus.loading) { _isSubmitting = false; diff --git a/lib/features/home/presentation/widgets/features_section.dart b/lib/features/home/presentation/widgets/features_section.dart index 72489f2..b5b4adc 100644 --- a/lib/features/home/presentation/widgets/features_section.dart +++ b/lib/features/home/presentation/widgets/features_section.dart @@ -479,25 +479,33 @@ class _FeaturesSectionState extends ConsumerState { const SizedBox(height: 8), // Location Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SvgPicture.asset( - 'assets/icons/location_filled_icon.svg', - width: 15, - height: 15, - placeholderBuilder: (_) => const Icon( - Icons.location_on, - color: AppColors.accentOrange, - size: 15, + Padding( + padding: const EdgeInsets.only(top: 2), + child: SvgPicture.asset( + 'assets/icons/location_filled_icon.svg', + width: 15, + height: 15, + placeholderBuilder: (_) => const Icon( + Icons.location_on, + color: AppColors.accentOrange, + size: 15, + ), ), ), const SizedBox(width: 4), - Text( - agent.location, - style: const TextStyle( - fontFamily: 'SourceSerif4', - fontSize: 14, - fontWeight: FontWeight.w500, - color: AppColors.primaryDark, + Expanded( + child: Text( + agent.location, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontFamily: 'SourceSerif4', + fontSize: 14, + fontWeight: FontWeight.w500, + color: AppColors.primaryDark, + ), ), ), ], diff --git a/lib/features/onboarding/presentation/screens/onboarding_screen.dart b/lib/features/onboarding/presentation/screens/onboarding_screen.dart index f990a3f..03d4fda 100644 --- a/lib/features/onboarding/presentation/screens/onboarding_screen.dart +++ b/lib/features/onboarding/presentation/screens/onboarding_screen.dart @@ -21,18 +21,18 @@ class _OnboardingScreenState extends State { iconAsset: 'assets/images/onboarding_1_icon.svg', iconWidth: 110, iconHeight: 100, - title: 'Connect with Top\nProfessionals', + title: 'Connect with Top Professionals', subtitle: - 'Professionals can list properties and find qualified\nbuyers faster than ever.', + 'Professionals can list properties and find qualified buyers faster than ever.', ), _OnboardingData( bgAsset: 'assets/images/onboarding_2_bg.svg', iconAsset: 'assets/images/onboarding_2_icon.svg', iconWidth: 83, iconHeight: 75, - title: 'Real help. Real professionals.\nInstantly.', + title: 'Real help. Real professionals. Instantly.', subtitle: - 'Chat with professionals and get answers about\nproperties instantly.', + 'Chat with professionals and get answers about properties instantly.', ), ]; @@ -208,150 +208,151 @@ class _OnboardingPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - children: [ - // Illustration section - takes upper portion - Expanded( - flex: 5, - child: Padding( - padding: const EdgeInsets.only(left: 0, top: 8), - child: Align( - alignment: Alignment.centerLeft, - child: SizedBox( - width: MediaQuery.of(context).size.width - 24, - child: Stack( - alignment: Alignment.center, - children: [ - // Background oval/pill shape with orange gradient - SvgPicture.asset( + // Scale the illustration to ~38% of screen height so it shrinks on small + // devices, leaving room for the title + subtitle without overflow. + final screenHeight = MediaQuery.of(context).size.height; + final illustrationHeight = (screenHeight * 0.38).clamp(220.0, 346.0); + + return SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Column( + children: [ + // Illustration section + Padding( + padding: const EdgeInsets.only(top: 8), + child: SizedBox( + width: MediaQuery.of(context).size.width - 24, + height: illustrationHeight, + child: Stack( + alignment: Alignment.center, + children: [ + // Background oval/pill shape with orange gradient + Positioned.fill( + child: SvgPicture.asset( data.bgAsset, - width: 382, - height: 346, fit: BoxFit.contain, ), - // Blurred decoration - bottom right - Positioned( - right: 20, - bottom: 20, - child: Container( - width: 160, - height: 160, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColors.accentOrange.withValues(alpha: 0.2), - boxShadow: [ - BoxShadow( - color: AppColors.accentOrange - .withValues(alpha: 0.15), - blurRadius: 40, - spreadRadius: 0, - ), - ], - ), + ), + // Blurred decoration - bottom right + Positioned( + right: 20, + bottom: 20, + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColors.accentOrange.withValues(alpha: 0.2), + boxShadow: [ + BoxShadow( + color: AppColors.accentOrange + .withValues(alpha: 0.15), + blurRadius: 40, + spreadRadius: 0, + ), + ], ), ), - // Blurred decoration - top left - Positioned( - left: 0, - top: 0, - child: Container( - width: 160, - height: 160, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: AppColors.accentOrange.withValues(alpha: 0.1), - boxShadow: [ - BoxShadow( - color: AppColors.accentOrange - .withValues(alpha: 0.08), - blurRadius: 40, - spreadRadius: 0, - ), - ], - ), + ), + // Blurred decoration - top left + Positioned( + left: 0, + top: 0, + child: Container( + width: 120, + height: 120, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: AppColors.accentOrange.withValues(alpha: 0.1), + boxShadow: [ + BoxShadow( + color: AppColors.accentOrange + .withValues(alpha: 0.08), + blurRadius: 40, + spreadRadius: 0, + ), + ], ), ), - // Main icon + small icons - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - data.iconAsset, - width: data.iconWidth, - height: data.iconHeight, - ), - const SizedBox(height: 16), - // Small property icons row - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - 'assets/images/onboarding_small_icon_1.svg', - width: 27, - height: 27, - ), - const SizedBox(width: 8), - SvgPicture.asset( - 'assets/images/onboarding_small_icon_2.svg', - width: 31.5, - height: 31.5, - ), - const SizedBox(width: 8), - SvgPicture.asset( - 'assets/images/onboarding_small_icon_3.svg', - width: 24, - height: 27, - ), - ], - ), - ], - ), - ], - ), + ), + // Main icon + small icons + Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + data.iconAsset, + width: data.iconWidth, + height: data.iconHeight, + ), + const SizedBox(height: 12), + // Small property icons row + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + 'assets/images/onboarding_small_icon_1.svg', + width: 27, + height: 27, + ), + const SizedBox(width: 8), + SvgPicture.asset( + 'assets/images/onboarding_small_icon_2.svg', + width: 31.5, + height: 31.5, + ), + const SizedBox(width: 8), + SvgPicture.asset( + 'assets/images/onboarding_small_icon_3.svg', + width: 24, + height: 27, + ), + ], + ), + ], + ), + ], ), ), ), - ), - // Text content section - Expanded( - flex: 3, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), + // Text content section + Padding( + padding: const EdgeInsets.fromLTRB(24, 16, 24, 16), child: Column( + mainAxisSize: MainAxisSize.min, children: [ - const SizedBox(height: 8), // Title Text( data.title, textAlign: TextAlign.center, style: const TextStyle( fontFamily: 'Fractul', - fontSize: 32, + fontSize: 26, fontWeight: FontWeight.w700, color: Color(0xFF0F172A), height: 1.25, letterSpacing: -0.8, ), ), - const SizedBox(height: 16), + const SizedBox(height: 12), // Subtitle Text( data.subtitle, textAlign: TextAlign.center, style: const TextStyle( fontFamily: 'SourceSerif4', - fontSize: 16, + fontSize: 15, fontWeight: FontWeight.w400, color: Color(0xFF475569), - height: 1.625, + height: 1.5, ), ), ], ), ), - ), - ], + ], + ), ); } } diff --git a/lib/features/profile/presentation/widgets/profile_settings_tab.dart b/lib/features/profile/presentation/widgets/profile_settings_tab.dart index 4c2e993..ba70109 100644 --- a/lib/features/profile/presentation/widgets/profile_settings_tab.dart +++ b/lib/features/profile/presentation/widgets/profile_settings_tab.dart @@ -467,47 +467,54 @@ class _ProfileSettingsTabState extends ConsumerState { } return AlertDialog( + scrollable: true, title: const Text('Change Email Address'), - content: SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'A verification link will be sent to your new email. Your email changes only after you click the link.', - style: TextStyle(fontSize: 13), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Text( + 'A verification link will be sent to your new email. Your email changes only after you click the link.', + style: TextStyle(fontSize: 13), + ), + const SizedBox(height: 16), + TextField( + controller: newEmailCtl, + keyboardType: TextInputType.emailAddress, + autocorrect: false, + enableSuggestions: false, + textCapitalization: TextCapitalization.none, + autofillHints: const [AutofillHints.email], + decoration: const InputDecoration( + labelText: 'New Email', + hintText: 'new@example.com', ), - const SizedBox(height: 16), - TextField( - controller: newEmailCtl, - keyboardType: TextInputType.emailAddress, - autocorrect: false, - textCapitalization: TextCapitalization.none, - decoration: const InputDecoration( - labelText: 'New Email', - hintText: 'new@example.com', - ), + ), + const SizedBox(height: 12), + TextField( + controller: passwordCtl, + obscureText: true, + autocorrect: false, + enableSuggestions: false, + // Empty autofillHints prevents iOS from showing the + // "Strong Password" suggestion bar, which was adding + // extra bottom inset and shifting the dialog upward. + autofillHints: const [], + decoration: const InputDecoration( + labelText: 'Current Password', ), + ), + if (localError != null) ...[ const SizedBox(height: 12), - TextField( - controller: passwordCtl, - obscureText: true, - decoration: const InputDecoration( - labelText: 'Current Password', + Text( + localError!, + style: const TextStyle( + color: Colors.red, + fontSize: 12, ), ), - if (localError != null) ...[ - const SizedBox(height: 12), - Text( - localError!, - style: const TextStyle( - color: Colors.red, - fontSize: 12, - ), - ), - ], ], - ), + ], ), actions: [ TextButton( diff --git a/lib/features/splash/presentation/screens/splash_screen.dart b/lib/features/splash/presentation/screens/splash_screen.dart index 954b8dd..0fb9608 100644 --- a/lib/features/splash/presentation/screens/splash_screen.dart +++ b/lib/features/splash/presentation/screens/splash_screen.dart @@ -1,18 +1,20 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:real_estate_mobile/core/constants/app_colors.dart'; +import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart'; -class SplashScreen extends StatefulWidget { +class SplashScreen extends ConsumerStatefulWidget { const SplashScreen({super.key}); @override - State createState() => _SplashScreenState(); + ConsumerState createState() => _SplashScreenState(); } -class _SplashScreenState extends State +class _SplashScreenState extends ConsumerState with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _fadeAnimation; @@ -43,11 +45,15 @@ class _SplashScreenState extends State final onboardingCompleted = prefs.getBool('onboarding_completed') ?? false; if (!mounted) return; - if (onboardingCompleted) { - context.go('/home'); - } else { + if (!onboardingCompleted) { context.go('/onboarding'); + return; } + // Agents land on /profile (Edit Profile tab); everyone else on /home. + final authState = ref.read(authProvider); + final isAgent = authState.status == AuthStatus.authenticated && + authState.user?.role == 'AGENT'; + context.go(isAgent ? '/profile' : '/home'); } @override diff --git a/lib/routing/app_router.dart b/lib/routing/app_router.dart index da4212f..663c36a 100644 --- a/lib/routing/app_router.dart +++ b/lib/routing/app_router.dart @@ -23,6 +23,7 @@ import 'package:real_estate_mobile/features/agents/presentation/screens/agent_ed import 'package:real_estate_mobile/features/profile/presentation/screens/payment_success_screen.dart'; import 'package:real_estate_mobile/features/splash/presentation/screens/splash_screen.dart'; import 'package:real_estate_mobile/features/onboarding/presentation/screens/onboarding_screen.dart'; +import 'package:real_estate_mobile/features/agents/presentation/screens/agent_home_screen.dart'; import 'package:real_estate_mobile/features/auth/presentation/screens/verify_2fa_screen.dart'; import 'package:real_estate_mobile/features/support_chat/presentation/screens/support_chat_screen.dart'; import 'package:real_estate_mobile/features/coming_soon/presentation/screens/coming_soon_screen.dart'; @@ -288,8 +289,8 @@ final routerProvider = Provider((ref) { ); }); -/// Always shows the user HomeScreen for /home. Agents reach their own -/// dashboard via the Edit Profile tab in the Profile section. +/// Reactively switches between HomeScreen and AgentHomeScreen based on auth. +/// Agents see their dashboard (profile view); users see the discovery home. class _HomeRouteWrapper extends ConsumerWidget { const _HomeRouteWrapper(); @@ -306,8 +307,10 @@ class _HomeRouteWrapper extends ConsumerWidget { ); } - // Home icon always shows the User Home Page regardless of role. - // Agents access their own dashboard via the Edit Profile tab in /profile. + if (authState.status == AuthStatus.authenticated && + authState.user?.role == 'AGENT') { + return const AgentHomeScreen(); + } return const HomeScreen(); } }