如何正确更新 firestore 数据库值

how to update firestore database value correctly

我正在努力在我的 Flutter 应用程序中构建基本的购物功能。我是编码和 Flutter 的新手。当用户单击 PlaceOrderPageContainer(按钮)以确认签出时,调用 addOrderDetails() 方法,然后更新 Firebase 数据库。除了添加为零的总金额之外,Firestore 数据库中的所有内容都在正确更新,无论购物车中的总金额如何。我在控制台中没有收到任何错误,但很明显我的代码编写不正确。任何帮助将不胜感激。如果有帮助,我可以添加任何其他代码。

    class ShoppingCartPage extends StatefulWidget {
  const ShoppingCartPage({Key? key}) : super(key: key);

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

class _ShoppingCartPageState extends State<ShoppingCartPage> {
  late double totalAmount;

  @override
  void initState() {
    super.initState();
    totalAmount = 0;
    Provider.of<TotalAmountProvider>(
      context,
      listen: false,
    ).display(0);
  }

  @override
  Widget build(BuildContext context) {
    return Consumer2<TotalAmountProvider, CartItemCounterProvider>(
      builder: (context, amountProvider, cartProvider, c) {
        return SafeArea(
          child: Scaffold(
            appBar: const ShoppingCartAppBar(),
            floatingActionButton: FloatingActionButton.extended(
              onPressed: () {
                if (ShoppingApp.sharedPreferences
                        .getStringList(
                          ShoppingApp.userCartList,
                        )
                        ?.length ==
                    1) {
                  Fluttertoast.showToast(msg: ToastString.cartEmpty);
                } else {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => AddressPage(
                        totalAmount: totalAmount,
                      ),
                    ),
                  );
                }
              },
              icon: const Icon(
                Icons.navigate_next,
              ),
              label: Text(
                ButtonString.checkOut.toUpperCase(),
              ),
            ),
            body: CustomScrollView(
              slivers: [
                SliverToBoxAdapter(
                  child:
                      Consumer2<TotalAmountProvider, CartItemCounterProvider>(
                    builder: (context, amountProvider, cartProvider, c) {
                      return Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Center(
                          child: cartProvider.count == 0
                              ? Container()
                              : Text(
                                  'Total Price: $${amountProvider.totalAmount.toString()}',
                                  style: Theme.of(context).textTheme.headline6,
                                ),
                        ),
                      );
                    },
                  ),
                ),
                StreamBuilder<QuerySnapshot>(
                    stream: ShoppingApp.firestore
                        .collection('items')
                        .where('shortInfo',
                            whereIn: ShoppingApp.sharedPreferences
                                .getStringList(ShoppingApp.userCartList))
                        .snapshots(),
                    builder: (context, AsyncSnapshot snapshot) {
                      return !snapshot.hasData
                          ? const AdaptiveCircularProgressSliver()
                          : snapshot.data.docs.isEmpty
                              ? const EmptyShoppingCartContainer()
                              : SliverList(
                                  delegate: SliverChildBuilderDelegate(
                                    (context, index) {
                                      ItemModel model = ItemModel.fromJson(
                                        snapshot.data.docs[index].data(),
                                      );
                                      if (index == 0) {
                                        totalAmount = 0;
                                        // totalAmount = model.price! + totalAmount;
                                      } else {
                                        totalAmount =
                                            model.price! + totalAmount;
                                      }
                                      if (snapshot.data?.docs.length - 1 ==
                                          index) {
                                        WidgetsBinding.instance!
                                            .addPostFrameCallback((timeStamp) {
                                          Provider.of<TotalAmountProvider>(
                                                  context,
                                                  listen: false)
                                              .display(totalAmount);
                                        });
                                      }
                                      return sourceInfo(
                                        model,
                                        context,
                                        removeCartFunction: () =>
                                            removeItemFromUserCart(
                                          model.shortInfo as String,
                                        ),
                                      );
                                    },
                                    childCount: snapshot.hasData
                                        ? snapshot.data?.docs.length
                                        : 0,
                                  ),
                                );
                    }),
              ],
            ),
          ),
        );
      },
    );
  }

  Future<void> removeItemFromUserCart(
    String shortInfoAsID,
  ) async {
    List<String>? tempCartList = ShoppingApp.sharedPreferences.getStringList(
      ShoppingApp.userCartList,
    );
    tempCartList?.remove(shortInfoAsID);

    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionUser)
        .doc(ShoppingApp.sharedPreferences.getString(
          ShoppingApp.userUID,
        ))
        .update({
      ShoppingApp.userCartList: tempCartList,
    }).then((value) {
      Fluttertoast.showToast(
        msg: ToastString.removeFromCart,
      );
      ShoppingApp.sharedPreferences.setStringList(
        ShoppingApp.userCartList,
        tempCartList as List<String>,
      );

      Provider.of<CartItemCounterProvider>(
        context,
        listen: false,
      ).displayResult();

      totalAmount = 0;
    });
  }
}

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

  final double totalAmount;

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

class _AddressPageState extends State<AddressPage> {
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: AdaptiveLayoutScaffold(
        appBar: const AddressPageAppBar(),
        floatingActionButton: const AddNewAddressFAB(),
        landscapeBodyWidget: Container(),
        portraitBodyWidget: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            const AddressPageHeadline(
              headlineText: ShoppingPageString.selectAddress,
            ),
            Consumer<AddressChangerProvider>(builder: (
              context,
              address,
              c,
            ) {
              return Flexible(
                child: StreamBuilder<QuerySnapshot>(
                    stream: ShoppingApp.firestore
                        .collection(ShoppingApp.collectionUser)
                        .doc(ShoppingApp.sharedPreferences
                            .getString(ShoppingApp.userUID))
                        .collection(ShoppingApp.subCollectionAddress)
                        .snapshots(),
                    builder: (context, snapshot) {
                      return !snapshot.hasData
                          ? const AdaptiveCircularProgressCenter()
                          : snapshot.data!.docs.isEmpty
                              ? const EmptyShippingAddressContainer()
                              : ListView.builder(
                                  itemCount: snapshot.data?.docs.length,
                                  shrinkWrap: true,
                                  itemBuilder: (context, index) {
                                    return AddressCard(
                                      addressID: snapshot.data?.docs[index].id
                                          as String,
                                      currentIndex: address.count,
                                      model: AddressModel.fromJson(
                                        snapshot.data?.docs[index].data()
                                            as Map<String, dynamic>,
                                      ),
                                      totalAmount: widget.totalAmount,
                                      value: index,
                                    );
                                  },
                                );
                    }),
              );
            }),
          ],
        ),
      ),
    );
  }
}

class AddressCard extends StatefulWidget {

  const AddressCard({
    Key? key,
    required this.addressID,
    required this.currentIndex,
    required this.model,
    required this.totalAmount,
    required this.value,
  }) : super(key: key);

  final String addressID;
  final int currentIndex;
  final AddressModel model;
  final double totalAmount;
  final int value;

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

class _AddressCardState extends State<AddressCard> {
  @override
  Widget build(BuildContext context) {
    return AddressCardContainer(
      onTap: () {
        Provider.of<AddressChangerProvider>(
          context,
          listen: false,
        ).displayResult(widget.value);
      },
      addressCardColumn: AddressCardColumn(
        children: [
          Row(
            children: [
              AddressCardRadioButton(
                groupValue: widget.currentIndex,
                onChanged: (value) {
                  Provider.of<AddressChangerProvider>(
                    context,
                    listen: false,
                  ).displayResult(
                    value as int,
                  );
                },
                value: widget.value,
              ),
              AddressCardContent(
                city: widget.model.city as String,
                fullName: widget.model.name as String,
                phoneNumber: widget.model.phoneNumber as String,
                postalCode: widget.model.postalCode as String,
                state: widget.model.state as String,
                streetAddress: widget.model.streetAddress as String,
              ),
            ],
          ),
          widget.value == Provider.of<AddressChangerProvider>(context).count
              ? ShippingAddressProceedButton(
                  onPressed: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (
                          context,
                        ) =>
                            PlaceOrderPaymentPage(
                          addressID: widget.addressID,
                          totalAmount: widget.totalAmount,
                        ),
                      ),
                    );
                  },
                )
              : Container(),
        ],
      ),
    );
  }
}

class PlaceOrderPaymentPage extends StatefulWidget {
  const PlaceOrderPaymentPage({
    Key? key,
    required this.addressID,
    required this.totalAmount,
  }) : super(key: key);

  final String addressID;
  final double totalAmount;

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

class _PlaceOrderPaymentPageState extends State<PlaceOrderPaymentPage> {
  @override
  Widget build(BuildContext context) {
    return AdaptiveLayoutScaffold(
      appBar: const PlaceOrderPaymentPageAppBar(),
      landscapeBodyWidget: Container(),
      portraitBodyWidget: PlaceOrderPageContainer(
        orderOnPressed: () => addOrderDetails(),
      ),
    );
  }

  void addOrderDetails() {
    final time = DateTime.now().millisecondsSinceEpoch;

    writeOrderDetailsForUser({
      ShoppingApp.addressID: widget.addressID,
      ShoppingApp.totalAmount: widget.totalAmount,
      'orderBy': ShoppingApp.sharedPreferences.getString(
        ShoppingApp.userUID,
      ),
      ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
        ShoppingApp.userCartList,
      ),
      ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
      ShoppingApp.orderTime: time.toString(),
      ShoppingApp.isSuccess: true,
    });

    writeOrderDetailsForAdmin({
      ShoppingApp.addressID: widget.addressID,
      ShoppingApp.totalAmount: widget.totalAmount,
      'orderBy': ShoppingApp.sharedPreferences.getString(
        ShoppingApp.userUID,
      ),
      ShoppingApp.productID: ShoppingApp.sharedPreferences.getStringList(
        ShoppingApp.userCartList,
      ),
      ShoppingApp.paymentDetails: ShoppingPageString.cashOnDelivery,
      ShoppingApp.orderTime: time.toString(),
      ShoppingApp.isSuccess: true,
    }).whenComplete(() => {
          emptyCartNow(),
        });
  }

  void emptyCartNow() {
    ShoppingApp.sharedPreferences.setStringList(ShoppingApp.userCartList, [
      'garbageValue',
    ]);
    List<String>? tempList = ShoppingApp.sharedPreferences.getStringList(
      ShoppingApp.userCartList,
    );

    FirebaseFirestore.instance
        .collection('users')
        .doc(ShoppingApp.sharedPreferences.getString(
          ShoppingApp.userUID,
        ))
        .update({
      ShoppingApp.userCartList: tempList,
    }).then((value) {
      ShoppingApp.sharedPreferences.setStringList(
        ShoppingApp.userCartList,
        tempList as List<String>,
      );
      Provider.of<CartItemCounterProvider>(
        context,
        listen: false,
      ).displayResult();
    });
    Fluttertoast.showToast(
      msg: ToastString.orderPlacedSuccessfully,
    );
    Navigator.pushReplacement(
      context,
      MaterialPageRoute(
        builder: (context) => const ShoppingPage(),
      ),
    );
  }

  Future<void> writeOrderDetailsForUser(
    Map<String, dynamic> data,
  ) async {
    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionUser)
        .doc(ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID))
        .collection(ShoppingApp.collectionOrders)
        .doc(
          ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
              data['orderTime'],
        )
        .set(data);
  }

  Future<void> writeOrderDetailsForAdmin(Map<String, dynamic> data) async {
    await ShoppingApp.firestore
        .collection(ShoppingApp.collectionOrders)
        .doc(
          ShoppingApp.sharedPreferences.getString(ShoppingApp.userUID)! +
              data['orderTime'],
        )
        .set(data);
  }
}


class CartItemCounterProvider extends ChangeNotifier {
  final int _counter = (ShoppingApp.sharedPreferences
              .getStringList(
                ShoppingApp.userCartList,
              )
              ?.length ??
          0) -
      1;
  int get count => _counter;

  Future<void> displayResult() async {
    
    int _counter = (ShoppingApp.sharedPreferences
                .getStringList(
                  ShoppingApp.userCartList,
                )
                ?.length ??
            0) -
        1;

    await Future.delayed(
        const Duration(
          milliseconds: 100,
        ), () {
      notifyListeners();
    });
  }
}

CartCheckOutFAB 首先总是用值 0 实例化,因为 ShoppingCartPage 状态没有改变。 您可以尝试将 Consumer2 作为 AdaptiveLayoutScaffold 的父级移动并实例化 CartCheckOutFAB amountProvider.totalAmount

  • 如果它不起作用,您可以提供 CartCheckOutFAB 小部件 class。