From 460e7cdcea7c5846c2b095c3c78a899ff8c15b23 Mon Sep 17 00:00:00 2001 From: Sultan khan Date: Tue, 3 Nov 2026 15:41:38 +0300 Subject: [PATCH] profile picture fixed. --- .../authentication_view_model.dart | 42 ++++--------------- .../profile_picture_view_model.dart | 18 ++++++-- .../profile_settings_view_model.dart | 33 ++++++++++++--- lib/presentation/home/landing_page.dart | 12 ++++++ .../widgets/profile_picture_widget.dart | 27 +++++++----- 5 files changed, 80 insertions(+), 52 deletions(-) diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index cb164a0c..04e66039 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -33,6 +33,7 @@ import 'package:hmg_patient_app_new/features/hmg_services/hmg_services_view_mode import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; +import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/symptoms_checker/symptoms_checker_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; @@ -52,7 +53,6 @@ import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:sms_otp_auto_verify/sms_otp_auto_verify.dart'; import '../insurance/insurance_view_model.dart'; -import '../profile_settings/profile_settings_repo.dart'; import 'models/request_models/get_user_mobile_device_data.dart'; import 'models/request_models/insert_patient_mobile_deviceinfo.dart'; import 'models/request_models/patient_insert_device_imei_request.dart'; @@ -1824,6 +1824,7 @@ class AuthenticationViewModel extends ChangeNotifier { _appState.setAppAuthToken = ""; _appState.setUserBloodGroup = ""; _appState.clearProfileImageCache(); // Clear profile image cache + GetIt.instance().clearProfileImageCache(); _appState.setSuperUserID = null; _appState.setIsChildLoggedIn = false; _appState.setFamilyFileTokenID = ""; @@ -1877,43 +1878,16 @@ class AuthenticationViewModel extends ChangeNotifier { try { log("Fetching profile image for patient ID: $patientID"); - // IMPORTANT: Clear old cache BEFORE fetching new image - // This ensures old data is removed immediately + // Clear old cache before fetching new image _appState.clearProfileImageCache(); log("🧹 Cleared profile image cache before fetch"); - final profileSettingsRepo = GetIt.instance(); - final result = await profileSettingsRepo.getProfileImage(patientID: patientID); + final profileSettingsVM = GetIt.instance(); + profileSettingsVM.clearProfileImageCache(); - result.fold( - (failure) { - // Silently fail - profile image is optional - log("Failed to fetch profile image: ${failure.message}"); - // Ensure cache is cleared even on failure - _appState.setProfileImageData = null; - }, - (apiResponse) { - if (apiResponse.data != null && apiResponse.data['Patient_GetProfileImageDataList'] != null) { - var imageList = apiResponse.data['Patient_GetProfileImageDataList']; - if (imageList is List && imageList.isNotEmpty) { - String? imageData = imageList[0]['ImageData']; - if (imageData != null && imageData.isNotEmpty) { - // Set new profile image data - this will update cache and notify all listeners - _appState.setProfileImageData = imageData; - log("✅ Profile image loaded and cached successfully for patient: $patientID"); - } else { - log("⚠️ Profile image data is empty for patient: $patientID"); - _appState.setProfileImageData = null; - } - } else { - log("⚠️ Profile image list is empty for patient: $patientID"); - _appState.setProfileImageData = null; - } - } else { - log("⚠️ No profile image data in response for patient: $patientID"); - _appState.setProfileImageData = null; - } - }, + await profileSettingsVM.getProfileImage( + patientID: patientID, + forceRefresh: true, ); } catch (e) { log("❌ Error fetching profile image: $e"); diff --git a/lib/features/profile_picture/profile_picture_view_model.dart b/lib/features/profile_picture/profile_picture_view_model.dart index 59198809..155ed77d 100644 --- a/lib/features/profile_picture/profile_picture_view_model.dart +++ b/lib/features/profile_picture/profile_picture_view_model.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; @@ -105,7 +106,7 @@ class ProfilePictureViewModel extends ChangeNotifier { _cachedImageDataHash = null; _selectedImage = null; - notifyListeners(); + safeNotifyListeners(); // Load new user's profile image _profileSettingsViewModel.getProfileImage( @@ -113,14 +114,25 @@ class ProfilePictureViewModel extends ChangeNotifier { forceRefresh: true, onSuccess: (data) { _tryCacheExistingImage(); - notifyListeners(); + safeNotifyListeners(); }, onError: (error) { - notifyListeners(); + safeNotifyListeners(); }, ); } + /// Safely dispatch notifyListeners to avoid setState() or markNeedsBuild() during build + void safeNotifyListeners() { + if (WidgetsBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) { + WidgetsBinding.instance.addPostFrameCallback((_) { + notifyListeners(); + }); + } else { + notifyListeners(); + } + } + /// Load profile image from API void loadProfileImage({bool forceRefresh = false}) { // Check if profile image is already loaded in AppState (skip if forcing refresh) diff --git a/lib/features/profile_settings/profile_settings_view_model.dart b/lib/features/profile_settings/profile_settings_view_model.dart index c61665c3..3450432d 100644 --- a/lib/features/profile_settings/profile_settings_view_model.dart +++ b/lib/features/profile_settings/profile_settings_view_model.dart @@ -1,6 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'package:get_it/get_it.dart'; import 'package:hmg_patient_app_new/core/app_state.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; @@ -351,15 +352,21 @@ class ProfileSettingsViewModel extends ChangeNotifier { Function(String)? onError, bool forceRefresh = false, // Add flag to force refresh }) async { + if (isProfileImageLoading && !forceRefresh) { + print('⏳ Profile image is already loading, skipping duplicate call'); + return; + } + print('🌐 Fetching profile image from API for patient: $patientID (forceRefresh: $forceRefresh)'); // IMPORTANT: Always clear old data BEFORE fetching // Do NOT use cached data - always fetch fresh from API profileImageData = null; + GetIt.instance().setProfileImageData = null; isProfileImageLoading = true; profileImageError = null; - notifyListeners(); // Notify to show loading state + safeNotifyListeners(); // Notify to show loading state final result = await profileSettingsRepo.getProfileImage(patientID: patientID); @@ -371,8 +378,9 @@ class ProfileSettingsViewModel extends ChangeNotifier { // Ensure data is cleared on failure profileImageData = null; + GetIt.instance().setProfileImageData = null; - notifyListeners(); + safeNotifyListeners(); if (onError != null) { onError(failure.message); } @@ -387,32 +395,47 @@ class ProfileSettingsViewModel extends ChangeNotifier { profileImageData = imageList[0]['ImageData']; if (profileImageData != null && profileImageData!.isNotEmpty) { - // ONLY store in ViewModel - AppState will be updated separately by auth flow + GetIt.instance().setProfileImageData = profileImageData; print('✅ Profile image loaded from API (length: ${profileImageData!.length})'); } else { profileImageData = null; + GetIt.instance().setProfileImageData = null; print('⚠️ Profile image data is empty in API response'); } } else { profileImageData = null; + GetIt.instance().setProfileImageData = null; print('⚠️ Profile image list is empty in API response'); } } else { profileImageData = null; + GetIt.instance().setProfileImageData = null; print('⚠️ No profile image data in API response'); } - notifyListeners(); // Notify to update UI with new/null data + safeNotifyListeners(); // Notify to update UI with new/null data onSuccess?.call(response.data); }, ); } + /// Safely dispatch notifyListeners to avoid setState() or markNeedsBuild() during build + void safeNotifyListeners() { + if (WidgetsBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) { + WidgetsBinding.instance.addPostFrameCallback((_) { + notifyListeners(); + }); + } else { + notifyListeners(); + } + } + /// Clear profile image data from ViewModel void clearProfileImageCache() { print('🧹 Clearing profile image from ViewModel'); profileImageData = null; - notifyListeners(); + GetIt.instance().setProfileImageData = null; + safeNotifyListeners(); } /// Sync profile image data from AppState - DISABLED diff --git a/lib/presentation/home/landing_page.dart b/lib/presentation/home/landing_page.dart index f475c022..4f128e2a 100644 --- a/lib/presentation/home/landing_page.dart +++ b/lib/presentation/home/landing_page.dart @@ -150,9 +150,21 @@ class _LandingPageState extends State { await authVM.handleNewImeiRegistration(isNavigate: false); } + if (!mounted) return; + if (appState.isAuthenticated) { Clarity.setCustomUserId(appState.getAuthenticatedUser()!.patientId.toString()); + final profileSettingsVM = context.read(); + if (profileSettingsVM.profileImageData == null && + (appState.getProfileImageData == null || appState.getProfileImageData!.isEmpty) && + !profileSettingsVM.isProfileImageLoading) { + final patientID = appState.getAuthenticatedUser()?.patientId; + if (patientID != null) { + profileSettingsVM.getProfileImage(patientID: patientID); + } + } + // habibWalletVM.initHabibWalletProvider(); // Wallet & Lakum data are fetched lazily when the user unhides the values. // habibWalletVM.getPatientBalanceAmount(); diff --git a/lib/presentation/profile_settings/widgets/profile_picture_widget.dart b/lib/presentation/profile_settings/widgets/profile_picture_widget.dart index 5fe71e1e..32601299 100644 --- a/lib/presentation/profile_settings/widgets/profile_picture_widget.dart +++ b/lib/presentation/profile_settings/widgets/profile_picture_widget.dart @@ -30,11 +30,12 @@ class _ProfilePictureWidgetState extends State { void initState() { super.initState(); - // Initialize view model + // Initialize view model synchronously so currentPatientId is immediately set + final profilePictureViewModel = context.read(); + profilePictureViewModel.initialize(); + WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; - final profilePictureViewModel = context.read(); - profilePictureViewModel.initialize(); profilePictureViewModel.triggerInitialLoad(); }); } @@ -42,18 +43,24 @@ class _ProfilePictureWidgetState extends State { @override void didChangeDependencies() { super.didChangeDependencies(); - // Check for user switch - final profilePictureViewModel = context.read(); - if (profilePictureViewModel.isInitialLoadTriggered) { - profilePictureViewModel.checkForUserSwitch(); - } + // Check for user switch safely after frame build to avoid markNeedsBuild during build + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + final profilePictureViewModel = context.read(); + if (profilePictureViewModel.isInitialLoadTriggered) { + profilePictureViewModel.checkForUserSwitch(); + } + }); } @override void didUpdateWidget(ProfilePictureWidget oldWidget) { super.didUpdateWidget(oldWidget); - // Check for user switch - context.read().checkForUserSwitch(); + // Check for user switch safely after frame build to avoid markNeedsBuild during build + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + context.read().checkForUserSwitch(); + }); } void _pickImage() {