4

Hi I have a screen for adding images. I use the multi_image_picker for picking the images. Upon selection of the images, all images picked will be shown in a grid view with a FloatingActionButton on top of each image for removal of each image. The problem is, when I click the button for removing an image, the last image is removed not the one I clicked on. Has anyone experienced this?

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:krakatoa/api/FileApi.dart';
import 'package:krakatoa/components/AssetView.dart';
import 'package:krakatoa/config/Themes.dart' as themes;
import 'package:krakatoa/mixins/SnackBarMixin.dart';
import 'package:krakatoa/podos/User.dart';
import 'package:krakatoa/utils/Common.dart' as common;
import 'package:multi_image_picker/multi_image_picker.dart';

class AddImageScreen extends StatefulWidget {
  final List<String> currentImageUrls;
  final String postUrl;

  AddImageScreen({this.currentImageUrls, @required this.postUrl});

  @override
  State<StatefulWidget> createState() => _AddImageState();
}

class _AddImageState extends State<AddImageScreen> with SnackBarMixin {
  List<Asset> _images = [];
  User _user;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: AppBar(
        title: Text('Add images'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(10.0),
        child: ListView(
          children: <Widget>[
            Container(
              padding: EdgeInsets.only(bottom: 10),
              child: Text(
                "Upload Images:",
                style: Theme.of(context).textTheme.headline,
              ),
            ),
            Container(
              padding: EdgeInsets.only(bottom: 10),
              child: GridView.count(
                shrinkWrap: true,
                crossAxisSpacing: 3,
                mainAxisSpacing: 3,
                crossAxisCount: 3,
                children: _renderPickedImages(),
              ),
            ),
            Container(
              child: FlatButton(
                child: Text('UPLOAD'),
                padding: EdgeInsets.symmetric(vertical: 15),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(30),
                ),
                color: themes.primaryColor,
                onPressed: _onUploadBtnPress,
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    for (var image in _images) {
      image.release();
    }
  }

  @override
  void initState() {
    super.initState();
    common.getCurrentUser().then((user) {
      if (user != null) {
        _user = user;
      } else {
        _user = User();
      }
    });
  }

  void showProgressAlert() {
    showDialog(
      context: context,
      builder: (context) {
        return WillPopScope(
          onWillPop: () async => false,
          child: AlertDialog(
            content: ListTile(
              leading: CircularProgressIndicator(
                value: null,
              ),
              title: Text('Processing...'),
            ),
          ),
        );
      },
      barrierDismissible: false,
    );
  }

  void _onAddImageBtnPress() async {
    List<Asset> resultList;

    try {
      resultList = await MultiImagePicker.pickImages(maxImages: 5, enableCamera: true);
    } on PlatformException catch (e) {
      debugPrint("AddImageScreen._onAddImageBtnPress: ${e.toString()}");
    }

    if (!mounted) return;

    if (resultList.isNotEmpty) {
      setState(() {
        _images.addAll(resultList);
      });
    }
  }

  void _onUploadBtnPress() {
    if (_images.isNotEmpty) {
      showProgressAlert();
      _uploadImages();
    } else {
      showSnackBarMessage("No images to upload", seconds: 5);
    }
  }

  void _removeImage(int index, Asset image) {
    debugPrint("INDEX: $index");
    debugPrint("Orig Image: ${_images[index].hashCode}");
    setState(() {
      _images.removeAt(index);
    });
  }

  List<Widget> _renderPickedImages() {
    List<Widget> imageWidgets = [];
    imageWidgets.add(InkWell(
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(
            width: 1,
            color: Colors.grey,
          ),
        ),
        child: Center(
          child: Icon(
            Icons.add,
            size: 60,
            color: Colors.grey,
          ),
        ),
      ),
      onTap: _onAddImageBtnPress,
    ));
    var ctr = 0;
    for (var image in _images) {
      imageWidgets.add(Container(
        child: Stack(
          fit: StackFit.expand,
          overflow: Overflow.visible,
          children: <Widget>[
            AssetView(image),
            Positioned(
              bottom: 0,
              right: 0,
              child: _ImageRemoveButton(
                index: ctr,
                removeItem: _removeImage,
                image: image,
              ),
            ),
          ],
        ),
      ));
      ctr++;
    }
    return imageWidgets;
  }

  Future<void> _uploadImages() async {
    if (_user.id <= 0) {
      showSnackBarMessage("User is not logged in");
      Navigator.of(context).pop("User is not logged in");
      return;
    }
    try {
      await FileApi.uploadImages(widget.postUrl, _images);

      Navigator.of(context).pop();
      Navigator.of(context).pop("Success");
    } on Exception catch (e) {
      debugPrint(e.toString());
      showSnackBarMessage(e.toString());
      Navigator.of(context).pop(e.toString());
    }
  }
}

class _ImageRemoveButton extends StatelessWidget {
  final Function removeItem;
  final Asset image;
  final int index;

  _ImageRemoveButton({this.removeItem, this.index, this.image});

  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      backgroundColor: Colors.white,
      mini: true,
      heroTag: "ImageAction_$index",
      isExtended: false,
      child: Icon(
        Icons.close,
        size: 15,
        color: Colors.black,
      ),
      onPressed: _onPress,
    );
  }

  void _onPress() {
    debugPrint("${this.hashCode}");
    debugPrint("Passed Image: ${image.hashCode}");
    removeItem(index, image);
  }
}
JZares
  • 187
  • 9
  • your problem lies on `Asset`, please [see this answer](https://stackoverflow.com/a/52482866/796963) – Feu Jan 14 '19 at 22:38
  • Hi I changed it and created a new class with asset passed. Then I created the 2 methods in the link you mentioned but it's still the same – JZares Jan 22 '19 at 16:28
  • 1
    did you solve it? having the same problem – Sophex Dec 29 '19 at 15:34
  • Did anyone find the solution I am also facing the same issue Its working for index greater than zero but when the index zero item that is first item is deleted it removes last item – Azhar May 04 '21 at 06:43

1 Answers1

3

add key: Key(YOUR_LIST.length.toString()), having KEY helps with the update of the ListView that worked for me on ListView.builder

Petrov
  • 66
  • 2