Connect Day 10: Cached Images File Uploads and UI Improvements

Cached Images File Uploads

Today, we worked on making profile images load faster with caching, allowing users to update profile pictures seamlessly, and ensuring everything looks good across devices.

GitHub Link: https://github.com/maitry4/Connect/

Cached Images File Uploads

Step 1: Modifying The Profile Page UI For Desktop

Go to the profile_card_widget.dart in the lib/features/profile/presentation/components

See In the Desktop version of the profile page you can see we have a circular avatar.

const CircleAvatar(
                radius: 50,
                child: Icon(Icons.person),
              ),

Cached Images File Uploads Cached Images File Uploads Cached Images File Uploads Cached Images File Uploads

Now, if there is a profile image and it got loaded correctly then, I want to show it as a cached image.

Why cached?

Because there is a chance that the user doesn’t have high-speed 10 G(joking😅) internet.

Add this package:

flutter pub add cached_network_image

Replace the circular avatar with the profile image.

CachedNetworkImage(
  imageUrl: widget.user.profileImageUrl,
  imageBuilder: (context, imageProvider) => CircleAvatar(
    radius: 50,
    backgroundImage: imageProvider,
  ),
  placeholder: (context, url) => const CircleAvatar(
    radius: 50,
    child: CircularProgressIndicator(),
  ),
  errorWidget: (context, url, error) => const CircleAvatar(
    radius: 50,
    child: Icon(Icons.person, size: 50, color: Colors.grey),
  ),
),

Just to test it out.

Go to imagekit’s user_profiles folder that you created earlier.

Upload a dummy image.

Copy its URL and paste it into the Firebase database profile image URL field.

Run and see if the image comes up on the desktop version of the profile page.

Cached Images File Uploads Cached Images File Uploads Cached Images File Uploads Cached Images File Uploads

Cached Images File Uploads

Pretty Cool, No??

Step 2: Configure For Mobile

Open your android/app/build.gradle file.

Locate the android block and update it as follows:

android {
    namespace "com.example.connect"
    compileSdkVersion 34
    ndkVersion flutter.ndkVersion

   ...

    defaultConfig {
        ...
        minSdkVersion 21
        targetSdkVersion 34
 ....     

Run flutter Clean Then, flutter pub get

Step 3: Modifying The Profile Page UI For Mobile

Go to the profile_page.dart in the lib/features/profile/presentation/pages in the _buildMobileLayout method

CircleAvatar(
              radius: res.width(20), 
              backgroundColor: Colors.grey[300],
              child: const Icon(Icons.person),
            ),

As you could have guessed already we will modify this to a cached image too.

CachedNetworkImage(
              imageUrl: usr.profileImageUrl,
              imageBuilder: (context, imageProvider) => CircleAvatar(
                radius: 50,
                backgroundImage: imageProvider,
              ),
              placeholder: (context, url) => const CircleAvatar(
                radius: 50,
                child: CircularProgressIndicator(),
              ),
              errorWidget: (context, url, error) => const CircleAvatar(
                radius: 50,
                child: Icon(Icons.person, size: 50, color: Colors.grey),
              ),
            ),

It’s the same as before except for the way we pass the image URL of course.

Run again this time on a phone.

The result should look like this:

profile page with image mobile version

Step 4: Modifying The Edit Profile Page UI For Desktop

Head over to the profile_edit_page.dart in lib/features/profile/presentation/pages

Create a new variable for the selected image and a new method to set the selected image.

Also, modify the updateProfile method.

File? _selectedImage;

  // Function to update profile
  void updateProfile() {
    final profileCubit = context.read<CProfileCubit>();

    if (bioTextController.text.isNotEmpty || _selectedImage != null) {
      profileCubit.updateProfile(
        uid: widget.profUser.uid,
        newBio: bioTextController.text,
        newProfileImage: _selectedImage, // Pass image file if selected
      );
    }
  }

  // Function to update selected image
  void setProfileImage(File? image) {
    setState(() {
      _selectedImage = image;
    });
  }

Pass these new values to the desktop layout widget of the profile edit page. Along with the current profile image.

CProfileEditDesktop(
        webImage: _webImage,
        bioController: bioTextController,
        updateProfile: updateProfile,
        profileImageUrl: widget.profUser.profileImageUrl, // Existing URL
        selectedImage: _selectedImage, // New selected image (if any)
        setProfileImage: setProfileImage, // Callback to update image
      ),

Take these arguments in the desktop version of the profile edit page. Before that convert it to a stateful widget

class CProfileEditDesktop extends StatefulWidget {
   Uint8List? webImage;
  final TextEditingController bioController;
  final VoidCallback updateProfile;
  final String profileImageUrl;
  final File? selectedImage;
  final void Function(File?, Uint8List?) setProfileImage;

  CProfileEditDesktop({
    super.key,
    required this.bioController,
    required this.updateProfile,
    required this.profileImageUrl,
    required this.selectedImage,
    required this.setProfileImage,
    required this.webImage,
  });

Now, create a method to pick an image in this file.


  Future<void> _pickImage() async {
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: FileType.image,
      withData: kIsWeb, // For web, load image as Uint8List
    );

    if (result != null) {
      if (kIsWeb) {
        _webImage = result.files.single.bytes; // Web: Use bytes
        setProfileImage(null, _webImage);
      } else {
        File newImage = File(result.files.single.path!); // Mobile: Use File
        setProfileImage(newImage, null);
      }
    }
  }

// Modify setProfileImage
  void setProfileImage(File? image, Uint8List? webImage) {
    setState(() {
      _selectedImage = image;
      _webImage = webImage;
    });
  }

Modify the Circular avatar and the pick image icon.

widget.selectedImage != null
                  ? CircleAvatar(
                      radius: 50,
                      backgroundImage: FileImage(widget.selectedImage!),
                    )
                  : widget.webImage != null
                      ? CircleAvatar(
                          radius: 50,
                          backgroundImage: MemoryImage(widget.webImage!), // For web
                        )
                      : CachedNetworkImage(
                          imageUrl: widget.profileImageUrl,
                          imageBuilder: (context, imageProvider) =>
                              CircleAvatar(
                            radius: 50,
                            backgroundImage: imageProvider,
                          ),
                          placeholder: (context, url) => const CircleAvatar(
                            radius: 50,
                            child: CircularProgressIndicator(),
                          ),
                          errorWidget: (context, url, error) =>
                              const CircleAvatar(
                            radius: 50,
                            child: Icon(Icons.person,
                                size: 50, color: Colors.grey),
                          ),
                        ),

Test the desktop version now.

Step 5: Modifying The Edit Profile Page UI For Mobile

For mobile, you need to do the same remove the CProfileImagePicker and then put the code above there too.

With a few tweaks, you’ll be able to do the same in the mobile version too.

Don’t forget to add the pickimage method.

Test it and it should work fine.

Conclusion:

With today’s updates, profile images now load faster, look better, and can be updated easily—all while keeping the UI clean and responsive.

Next up? We’ll enhance the profile edit experience further and refine the flow to make updates feel instant & seamless.

If you’ve ever worked on a profile UI, how did you handle image uploads & responsiveness? Let me know! 🚀

Leave a Reply