unselected
unselected

Reputation: 109

Flutter - Image.memory not refreshing after source change

I have a page that allows users to upload documents (as images). I have structured my page in a way that for each document type that can be uploaded a Document_Upload widget is used to reduce the amount of repeated code.

On initial load I use a FutureBuilder to get all the documents the user has already uploaded from our REST Api and then populate each Document_Upload widget with the relevant data.

On successful upload our REST Api returns the new image back to the Flutter app as a Byte Array so it can be displayed.

The problem I am currently facing is that no matter what I try the image widget (Image.memory) does not display the new image, it just stays on the old one. I have tried almost everything I can think of/ find online to resolve this issue, including:

I am starting to question if this is an issue related to Image.memory itself, however, using Image.File / Image.network is not an option with our current requirement.

Refreshing the page manually causes the new image to show up.

My code is as follows:

documents_page.dart

class DocumentsPage extends StatefulWidget {
  @override
  _DocumentsPageState createState() => _DocumentsPageState();
}

class _DocumentsPageState extends State<DocumentsPage>
    with SingleTickerProviderStateMixin {
  Future<Personal> _getUserDocuments;
  Personal _documents;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _getUserDocuments = sl<AccountProvider>().getUserDocuments();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: SafeArea(
        child: Center(
            child: Padding(
          padding: EdgeInsets.all(20),
          child: Container(
              constraints: BoxConstraints(maxWidth: 1300),
              child: buildFutureBuilder(context)),
        )),
      ),
    );
  }

  Widget buildFutureBuilder(BuildContext context) {
    var screenSize = MediaQuery.of(context).size;
    return FutureBuilder<Personal>(
        future: _getUserDocuments,
        builder: (context, AsyncSnapshot<Personal> snapshot) {
          if (!snapshot.hasData) {
            return Text("Loading");
          } else {
            if (snapshot.data == null) {
              return Center(child: Text('Error: ${snapshot.error}'));
            } else {
              _documents = snapshot.data;

              return Column(
                children: [
                  SizedBox(height: 20.0),
                  Text(
                    "DOCUMENTS",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        fontSize: 25,
                        fontWeight: FontWeight.bold,
                        color: AppColors.navy),
                  ),
                  Container(
                    constraints: BoxConstraints(maxWidth: 250),
                    child: Divider(
                      color: AppColors.darkBlue,
                      height: 20,
                    ),
                  ),
                  Container(
                      margin: EdgeInsets.only(top: 5.0, bottom: 5.0),
                      child: Text(
                          "These documents are required in order to verify you as a user",
                          style: TextStyle(fontSize: 14))),
                  Container(
                      margin: EdgeInsets.only(bottom: 25.0),
                      child: Text("View our Privacy Policy",
                          style: TextStyle(fontSize: 14))),
                  Container(
                      child: screenSize.width < 768
                          ? Column(
                              children: [
                                DocumentUpload(
                                    imageType: "ID",
                                    imageString: _documents.id),
                                DocumentUpload(
                                  imageType: "Drivers License Front",
                                  imageString: _documents.driversLicenseFront,
                                ),
                                DocumentUpload(
                                  imageType: "Drivers License Back",
                                  imageString: _documents.driversLicenseBack,
                                )
                              ],
                            )
                          : Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                  DocumentUpload(
                                      imageType: "ID",
                                      imageString: _documents.id),
                                  DocumentUpload(
                                    imageType: "Drivers License Front",
                                    imageString: _documents.driversLicenseFront,
                                  ),
                                  DocumentUpload(
                                    imageType: "Drivers License Back",
                                    imageString: _documents.driversLicenseBack,
                                  ),
                                ])),
                  Container(
                      child: screenSize.width < 768
                          ? Container()
                          : Padding(
                              padding:
                                  EdgeInsets.only(top: 10.0, bottom: 10.0))),
                  Container(
                      child: screenSize.width < 768
                          ? Column(
                              children: [
                                DocumentUpload(
                                  imageType: "Selfie",
                                  imageString: _documents.selfie,
                                ),
                                DocumentUpload(
                                  imageType: "Proof of Residence",
                                  imageString: _documents.proofOfResidence,
                                ),
                                Container(width: 325)
                              ],
                            )
                          : Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                  DocumentUpload(
                                    imageType: "Selfie",
                                    imageString: _documents.selfie,
                                  ),
                                  DocumentUpload(
                                    imageType: "Proof of Residence",
                                    imageString: _documents.proofOfResidence,
                                  ),
                                  Container(width: 325)
                                ])),
                ],
              );
            }
          }
        });
  }
}

document_upload.dart

class DocumentUpload extends StatefulWidget {
  final String imageType;
  final String imageString;

  const DocumentUpload({this.imageType, this.imageString});

  @override
  _DocumentUploadState createState() => _DocumentUploadState();
}

class _DocumentUploadState extends State<DocumentUpload> {
  String _imageType;
  String _imageString;
  bool uploadPressed = false;
  Image _imageWidget;

  @override
  Widget build(BuildContext context) {
    setState(() {
      _imageType = widget.imageType;
      _imageString = widget.imageString;

      _imageWidget =
          new Image.memory(base64Decode(_imageString), fit: BoxFit.fill);
    });

    return Container(
        constraints: BoxConstraints(maxWidth: 325),
        height: 200,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(20),
          boxShadow: [
            new BoxShadow(
              color: AppColors.lightGrey,
              blurRadius: 5.0,
              offset: Offset(0.0, 3.0),
            ),
          ],
        ),
        child: Card(
            color: Colors.white,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(20.0),
            ),
            child: Column(children: <Widget>[
              Padding(padding: EdgeInsets.only(top: 5.0)),
              Row(
                //ROW 1
                children: <Widget>[
                  Expanded(
                    child: Text(
                      _imageType,
                      textAlign: TextAlign.center,
                      style: TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                          color: AppColors.darkBlue),
                    ),
                  ),
                ],
              ),
              Row(
                //ROW 2
                children: <Widget>[
                  Expanded(
                    child: Container(
                        padding: EdgeInsets.only(left: 5.0, bottom: 5.0),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(20.0),
                          child: _imageWidget,
                        )),
                  ),
                  Consumer<AccountProvider>(
                      builder: (context, provider, child) {
                    return Padding(
                        padding: EdgeInsets.all(10.0),
                        child: Column(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: <Widget>[
                              Padding(
                                  padding:
                                      EdgeInsets.only(top: 5.0, bottom: 5.0),
                                  child: Icon(Icons.star,
                                      size: 20, color: AppColors.darkBlue)),
                              Padding(
                                  padding:
                                      EdgeInsets.only(top: 5.0, bottom: 5.0),
                                  child: Text('Drag file here or',
                                      textAlign: TextAlign.center)),
                              Padding(
                                  padding:
                                      EdgeInsets.only(top: 5.0, bottom: 5.0),
                                  child: DynamicGreyButton(
                                    title: uploadPressed
                                        ? "Uploading ..."
                                        : "Browse",
                                    onPressed: () async {
                                      FilePickerResult result =
                                          await FilePicker.platform.pickFiles(
                                              type: FileType.custom,
                                              allowedExtensions: [
                                            'jpg',
                                            'jpeg',
                                            'png'
                                          ]);
                                      if (result != null) {
                                        uploadPressed = true;
                                        Uint8List file =
                                            result.files.single.bytes;
                                        String fileType =
                                            result.files.single.extension;

                                        await provider
                                            .doUploadDocument(
                                                _imageType, file, fileType)
                                            .then((uploadResult) {
                                          if (uploadResult == null ||
                                              uploadResult == '') {
                                            showToast(
                                                "Document failed to upload");
                                            return;
                                          } else {
                                            showToast("Document uploaded",
                                                Colors.green, "#66BB6A");
                                            uploadPressed = false;
                                            _imageString = uploadResult;
                                            setState(() {});
                                          }
                                        });
                                      } else {
                                        // User canceled the picker
                                        uploadPressed = false;
                                      }
                                    },
                                  ))
                            ]));
                  })
                ],
              ),
            ])));
  }
}

Image Upload HTTP Call

  @override
  Future uploadDocuments(DocumentsUpload model) async {
    final response = await client.post(
        Uri.https(appConfig.baseUrl, "/api/Account/PostDocuments_Flutter"),
        body: jsonEncode(model.toJson()),
        headers: <String, String>{
          'Content-Type': 'application/json'
        });

    if (response.statusCode == 200) {
      var data = json.decode(response.body);
      return data;
    } else {
      return "";
    }
  }

EDIT: Attached GIF of current behaviour.

enter image description here

I am pretty much out of ideas at this point, any help would be greatly appreciated.

Upvotes: 3

Views: 2574

Answers (1)

unselected
unselected

Reputation: 109

Came up with a solution. I created a second variable to hold the new image string and showed an entirely new image widget once the second variable had value.

String _newImage;

In the success of the upload...

_newImage = uploadResult;
setState(() {});

Image widget...

child: (_newImage == null || _newImage == '')
         ? new Image.memory(base64Decode(_imageString), fit: BoxFit.fill)
         : new Image.memory(base64Decode(_newImage), fit: BoxFit.fill)

Not a very elegant solution, but it's a solution, but also not necessarily the answer as to why the original issue was there.

Upvotes: 1

Related Questions