skip to Main Content

currently I did applied new http POST request to upload profile picture. I have several pages that needed the profile picture such as profile page and my details page. right now, every time I upload new profile picture, the profile picture in my details page not updating right away. I need to navigate back to profile page and come back to my details page then the profile picture updated. I have been stuck for 5 days doing this things. can anyone help me?

currently, this is my implementation. I have tried to use blocbuilder inside the Stack but after upload new image, it just keep reloading. need to go back to home page navigate to profile page then my details page then it will working fine. i also tried to change the NetworkImage() into FileImage() if image != null but then I got this error Cannot retrieve length of file, path = ‘https://abcde.my/0/12/1’ (OS Error: No such file or directory, errno = 2). i also tried to change the way im structuring pickImageFromSource() but yeah still the same, the profile picture not right away updating.

Im expecting for the profile picture to right away updating after user pick new image. no need to go to profile page to get the latest profile picture in my details page.

API service

Future<http.Response> uploadProfilePicture(File? file) async {
    final List<int> imageBytes = file!.readAsBytesSync();
    final base64Image = base64Encode(imageBytes);
    final userLoginToken = await AppSharedPreferences.getUserLoginToken();

    try {
      final timeStamp = DateTimeHelper().apiRequiredTimeStamp();
      final signature = await EncryptionService.apiSignature(
          apiCodeName: 'UploadProfilePic',
          timeStamp: timeStamp,
          hasLoginToken: true);

      var body = {
        "Channel": "B",
        "LoginToken": userLoginToken,
        "ProfileImgFileContent": base64Image,
        "ProfileImgFileName":
            file.path.split('/').last, // Use the file name from the path
        "ProfileImgFileSize": imageBytes.length.toString(),
        "ProfileImgFileType":
            'image/${file.path.split('.').last.toLowerCase()}', // Use the file extension for type
      };

      final response = await http.post(
        Uri.parse('${AppConfig.development().apiBaseUrl}/UploadProfilePic'),
        headers: {
          "Content-Type": "application/json"
        },
        body: jsonEncode(body),
      );

      print('upload pp timestamp: $timeStamp');
      print('upload pp signature: $signature');
      print('upload pp response status code: ${response.statusCode}');

      return response;
    } catch (error) {
      throw Exception('Failed to update profile picture.');
    }
  }

Repository

class ProfileContentRepository {
  static final ProfileContentRepository _profileContentRepository =
      ProfileContentRepository._internal();

  factory ProfileContentRepository() {
    return _profileContentRepository;
  }

  ProfileContentRepository._internal();

  final apiService = ApiService();

  Future<http.Response> uploadProfilePicture(File? file) async {
    return apiService.uploadProfilePicture(file);
  }
}

Inside the Cubit

Future<void> uploadProfilePicture(File? image) async {
    final apiResponse =
        await profileContentRepository.uploadProfilePicture(image);

    if (apiResponse.statusCode == 200) {
      print('Profile picture uploaded successfully');
      fetchProfileContent();
    } else {
      emit(ProfileErrorState(
          error:
              'Failed to upload profile picture: ${apiResponse.statusCode} - ${apiResponse.body}'));
    }
  }

the UI part

class ProfilePageContent extends StatelessWidget {
  final MemberProfile memberProfile;

  const ProfilePageContent({
    Key? key,
    required this.memberProfile,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MyDetails(
      memberProfile: memberProfile,
    );
  }
}

class MyDetails extends StatefulWidget {
  const MyDetails({
    required this.memberProfile,
    Key? key,
  }) : super(key: key);

  final MemberProfile memberProfile;

  @override
  State<MyDetails> createState() => __MyDetailsState();
}

class __MyDetailsState extends State<MyDetails> {
  final _formKey = GlobalKey<FormState>();
  File? image;

  bool isLoading = false;
  late ProfileContentCubit profileContentCubit;

  @override
  void initState() {
    profileContentCubit = BlocProvider.of<ProfileContentCubit>(context);
    getMemberInfo();
    super.initState();
  }

  getMemberInfo() async {
    setState(() {
      isLoading = true;
    });
    image = widget.memberProfile.memberInfo!.profileImage != ""
        ? File(widget.memberProfile.memberInfo!.profileImage!)
        : null;

    setState(() {
      isLoading = false;
    });
  }

  Future pickImage() async {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Choose Image Source'),
          actions: [
            TextButton(
              onPressed: () async {
                Navigator.of(context).pop();
                await pickImageFromSource(ImageSource.gallery);
              },
              child: const Text('Gallery'),
            ),
            TextButton(
              onPressed: () async {
                Navigator.of(context).pop();
                await pickImageFromSource(ImageSource.camera);
              },
              child: const Text('Camera'),
            ),
          ],
        );
      },
    );
  }

  Future<void> pickImageFromSource(ImageSource source) async {
    try {
      final pickImg = await ImagePicker().pickImage(source: source);

      print('pickIMG $pickImg');
      print('BEFOREEE $image');
      if (pickImg != null) {
        // Perform the asynchronous work outside of setState
        final pickedImage = File(pickImg.path);
        print('Picked Image Path: ${pickedImage.path}');
        // Update the state synchronously
        context.read<ProfileContentCubit>().uploadProfilePicture(pickedImage);
        setState(() {
          evictImage();
          image = pickedImage;
          print('AFTERR $image');
        });
      } else {
        const Text('No photo was selected or taken');
      }
    } on PlatformException {
      throw Exception('Cannot pick image!');
    }
  }

  void evictImage() {
    final NetworkImage provider =
        NetworkImage(widget.memberProfile.memberInfo!.profileImage!);
    provider.evict().then<void>((bool success) {
      if (success) {
        debugPrint('CACHEEEEEE removed image!');
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    updateMemberInfo() {
      if (_formKey.currentState!.validate()) {
        _formKey.currentState!.save();

        context
            .read<ProfileContentCubit>()
            .updateMemberInfo(widget.memberProfile.memberInfo!);

        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: const Text(
              'Profile Updated',
              style: TextStyle(
                color: Colors.black,
              ),
            ),
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          ),
        );
      }
    }
    return Scaffold(
      body: isLoading
          ? const Center(
              child: CircularProgressIndicator(),
            )
          : SingleChildScrollView(
              child: Container(
                padding:
                    const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
                child: Column(
                  children: [
                    Stack(
                      children: [
                        image != null
                            ? SizedBox(
                                width: 120,
                                height: 120,
                                child: CircleAvatar(
                                  radius: 100,
                                  backgroundImage: NetworkImage(widget
                                      .memberProfile.memberInfo!.profileImage!),
                                ),
                              )
                            : SizedBox(
                                width: 120,
                                height: 120,
                                child: CircleAvatar(
                                  backgroundColor: Colors.green.shade200,
                                  radius: 100,
                                  child: Text(
                                    widget.memberProfile.memberInfo!.fullName
                                        .trim()[0],
                                    style: const TextStyle(
                                      fontSize: 70,
                                    ),
                                  ),
                                ),
                              ),
                        Positioned(
                          bottom: 0,
                          right: 0,
                          child: InkWell(
                            onTap: pickImage,
                            child: Container(
                              width: 35,
                              height: 35,
                              decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(100),
                                  color: Theme.of(context)
                                      .colorScheme
                                      .inversePrimary),
                              child: const Icon(Icons.camera_alt_rounded,
                                  color: Colors.black, size: 20),
                            ),
                          ),
                        ),
                      ],
                    ),

2

Answers


  1. Does fetchProfileContent() in your Cubit emit the new state ? It’s not part of the code you’ve posted.
    If not, that will be your problem, since you’re updating the image on the server and on status == 200 you’re not emitting the updated state to the app.

    Login or Signup to reply.
  2. In this if in your cubit you do not emit new state on statusCode==200.

    if (apiResponse.statusCode == 200) {
      print('Profile picture uploaded successfully');
      fetchProfileContent();
    } else {
      emit(ProfileErrorState(
          error:
              'Failed to upload profile picture: ${apiResponse.statusCode} - ${apiResponse.body}'));
    }
    

    Try something like:

    if (apiResponse.statusCode == 200) {
      print('Profile picture uploaded successfully');
      fetchProfileContent();
      emit(ProfileSuccessState());
    }
    

    Of course if you have ProfileSuccessState created

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search