skip to Main Content

I’m using a flutter app connected to my django 3.2 REST api on my GCP Ubuntu VM. My api media folder as defined in my settings.py is ./media —> which is the root folder of the api.

Since, The profile avatar details doesn’t reflect even inside the auth directory under my username , I have narrowed it down to the flutter app itself which is not sending the image to the backend.

Besides, here is what happens on the frontend : The profile pic gets shown inside the profile box after using pick image but it fails(Nothing happens) when I click save which sends a http patch request and returns a success from backend But, the profile picture is again empty. This is something that I’m not able to figure on my own, I’m uploading the avatar file flutter code below:

enum MYAvatarSize { extraSmall, small, medium, large, extraLarge }

enum MYAvatarType { user, community }

class MYAvatar extends StatelessWidget {
  final String? avatarUrl;
  final PlatformFile? avatarFile;
  final MYAvatarSize? size;
  final VoidCallback? onPressed;
  final double? borderWidth;
  final bool isZoomable;
  final double? borderRadius;
  final double? customSize;

  static const double AVATAR_SIZE_EXTRA_SMALL = 20.0;
  static const double AVATAR_SIZE_SMALL = 30.0;
  static const double AVATAR_SIZE_MEDIUM = 40.0;
  static const double AVATAR_SIZE_LARGE = 80.0;
  static const double AVATAR_SIZE_EXTRA_LARGE = 100.0;
  static const String DEFAULT_AVATAR_ASSET =
      'assets/images/fallbacks/avatar-fallback.jpg';
  static const double avatarBorderRadius = 10.0;

  static double getAvatarSize(MYAvatarSize size) {
    late double avatarSize;

    switch (size) {
      case MYAvatarSize.extraSmall:
        avatarSize = AVATAR_SIZE_EXTRA_SMALL;
        break;
      case MYAvatarSize.small:
        avatarSize = AVATAR_SIZE_SMALL;
        break;
      case MYAvatarSize.medium:
        avatarSize = AVATAR_SIZE_MEDIUM;
        break;
      case MYAvatarSize.large:
        avatarSize = AVATAR_SIZE_LARGE;
        break;
      case MYAvatarSize.extraLarge:
        avatarSize = AVATAR_SIZE_EXTRA_LARGE;
        break;
    }

    return avatarSize;
  }

  const MYAvatar(
      {Key? key, this.avatarUrl,
      this.size = MYAvatarSize.small,
      this.onPressed,
      this.avatarFile,
      this.borderWidth,
      this.isZoomable = false,
      this.borderRadius,
      this.customSize}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    MYAvatarSize finalSize = size ?? MYAvatarSize.small;
    double avatarSize = customSize ?? getAvatarSize(finalSize);

    Widget finalAvatarImage;

    if (avatarFile != null) {
      finalAvatarImage = FadeInImage(
        fit: BoxFit.cover,
        height: avatarSize,
        width: avatarSize,
        placeholder: const AssetImage(DEFAULT_AVATAR_ASSET),
        image: FileImage(File(avatarFile!.path!)),

      );
    } else if (avatarUrl != null) {
      finalAvatarImage = Image(
          height: avatarSize,
          width: avatarSize,
          fit: BoxFit.cover,
          image: AdvancedNetworkImage(avatarUrl!,
              useDiskCache: true,
              fallbackAssetImage: DEFAULT_AVATAR_ASSET,
              retryLimit: 0));

      if (isZoomable) {
        finalAvatarImage = GestureDetector(
          child: finalAvatarImage,
          onTap: () {
            MyappNetworkProviderState myappProvider =
                MyappNetworkProvider.of(context);
            myappProvider.dialogService.showZoomablePhotoBoxView(
                imageUrl: avatarUrl!, context: context);
          },
        );
      }
    } else {
      finalAvatarImage = _getAvatarPlaceholder(avatarSize);
    }

    Widget avatar = ClipRRect(
      borderRadius: BorderRadius.circular(borderRadius ?? avatarBorderRadius),
      child: finalAvatarImage,
    );

    if (onPressed == null) return avatar;

    return GestureDetector(
      onTap: onPressed,
      child: avatar,
    );
  }

  Widget _getAvatarPlaceholder(double avatarSize) {
    return Image.asset(
      DEFAULT_AVATAR_ASSET,
      height: avatarSize,
      width: avatarSize,
    );
  }
}

The suspicious lines are the following :

image: FileImage(File(avatarFile.path))  

image:AdvancedNetworkImage(avatarUrl,...)

I was initially getting the following errors on the above statements:

The argument type 'String?' can't be assigned to the parameter type 'String' ---> for both Lines 1 & 2

The property 'path' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!') ---> for Line 1.

I did a quick fix and the resultant code is :

image: FileImage(File(avatarFile!.path!))
image: AdvancedNetworkImage(avatarUrl!,...)

which are parts of original question. No compile errors but the avatar image doesn’t get updated.

2

Answers


  1. Chosen as BEST ANSWER

    Had to change the updateUser() function which awaits response from the server api backend.

    if (avatar is File) 
    {body['avatar'] = avatar}
    

    to

    if (avatar is PlatformFile) 
    {body['avatar'] = avatar}
    

  2. TLDR summarization if anyone has a similar problem and does not want to read all of the comments above.

    The problem was the following:
    After changing the type of an attribute (here a File for a profile avatar picture) inside of the UI and then adjusting the related code fragments the affected attribute was no longer updated on the backend.

    This happened because the api for sending the data from the client to the server (to update the profile) accepted some attributes of the profile as dynamic type, so it didn’t produce any errors, or warnings on the initial code refactoring.

    But inside of that method before converting the attributes of the profile to json, the affected attribute (in this case the dynamic avatar), it’s type was checked against the old type (so File and not the new Platformfile) which lead to no data for the attribute being send to the server on updating.

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