1

当用户试图编辑他们的信息时,我试图将我的 UserData 读入表单字段。我可以写入 Firebase,但我无法读取用户数据并将其显示到内置字段中。每个 userData 都以登录用户的 mid 作为 userData 的 id 来存储,以便区分。

我错过了什么?请参阅下文了解我的尝试。

这是我的 UserData 模型:

class UserData {
  String id;
  String firstName;
  String lastName;
  String phoneNumber;
  String role;
  String businessName;
  String businessType;
  String streetAddress;
  String city;
  String state;
  String postcode;
  String country;
  String businessTradingCurrency;
  Timestamp createdAt;
  Timestamp updatedAt;

  UserData(
    this.id,
    this.firstName,
    this.businessTradingCurrency,
    this.businessType,
    this.businessName,
    this.city,
    this.country,
    this.createdAt,
    this.lastName,
    this.phoneNumber,
    this.postcode,
    this.role,
    this.state,
    this.streetAddress,
    this.updatedAt,
  );

  UserData.fromMap(Map<String, dynamic> data) {
    id = data['id'];
    firstName = data['first_name'];
    lastName = data['last_name'];
    phoneNumber = data['phone_number'];
    businessTradingCurrency = data['trading_currency'];
    role = data['role'];
    businessName = data['business_name'];
    businessType = data['business_type'];
    streetAddress = data['street_address'];
    city = data['city'];
    postcode = data['postcode'];
    state = data['state'];
    country = data['country'];
    createdAt = data['created_at'];
    updatedAt = data['updated_at'];
  }

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'first_name': firstName,
      'last_name': lastName,
      'phone_number': phoneNumber,
      'role': role,
      'trading_currency': businessTradingCurrency,
      'business_name': businessName,
      'business_type': businessType,
      'street_address': streetAddress,
      'city': city,
      'postcode': postcode,
      'state': state,
      'country': country,
      'created_at': createdAt,
      'updated_at': updatedAt,
    };
  }
}

这是我的 UserData 通知程序类:

class UserDataNotifier with ChangeNotifier {
  UserData _currentLoggedInUserData;

  CollectionReference userDataRef = Firestore.instance.collection('userData');

  UserData get currentLoggedInUserData => _currentLoggedInUserData;

  set currentLoggedInUserData(UserData userData) {
    _currentLoggedInUserData = userData;
    notifyListeners();
  }

  Future<void> getUserData() async {
    String userId = (await FirebaseAuth.instance.currentUser()).uid.toString();
    DocumentSnapshot result =
        await Firestore.instance.collection('userData').document(userId).get();

    _currentLoggedInUserData = result.data as UserData;
    print('Phone Number: ${_currentLoggedInUserData.phoneNumber}');

    notifyListeners();
  }

  Future createOrUpdateUserData(UserData userData, bool isUpdating) async {
    String userId = (await FirebaseAuth.instance.currentUser()).uid;

    if (isUpdating) {
      userData.updatedAt = Timestamp.now();

      await userDataRef.document(userId).updateData(userData.toMap());
      print('updated userdata with id: ${userData.id}');
    } else {
      userData.createdAt = Timestamp.now();

      DocumentReference documentReference = userDataRef.document(userId);

      userData.id = documentReference.documentID;

      await documentReference.setData(userData.toMap(), merge: true);
      print('created userdata successfully with id: ${userData.id}');
    }
    notifyListeners();
  }
}

这是我的编辑用户配置文件表单:

class ProfileFormScreen extends StatefulWidget {
  static const String id = 'profile_form';

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

class _ProfileFormScreenState extends State<ProfileFormScreen> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  UserData _currentLoggedInUserData;
  bool showSpinner = false;

  //global declarations
  String selectedBusinessTypeDropDownValue = 'Fashion';
  String selectedCurrencyDropDownValue = 'AUD: Australian Dollar';
  String selectedCountryDropDownValue = 'Australia';
  String email;

  @override
  void initState() {
    super.initState();

    UserDataNotifier userDataNotifier =
        Provider.of<UserDataNotifier>(context, listen: false);

    if (userDataNotifier.currentLoggedInUserData != null) {
      _currentLoggedInUserData = userDataNotifier.currentLoggedInUserData;
    } else {
      _currentLoggedInUserData = UserData(
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    UserDataNotifier userDataNotifier =
        Provider.of<UserDataNotifier>(context, listen: false);
    print('Logged in user id: ${_currentLoggedInUserData.id}');
    _saveUserData() async {
      if (!_formKey.currentState.validate()) {
        return;
      }
      _formKey.currentState.save();
      userDataNotifier.createOrUpdateUserData(_currentLoggedInUserData, true);
      Navigator.pop(context);
    }

    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Profile'),
        actions: <Widget>[
          FlatButton(
              onPressed: () => _saveUserData(),
              child: Icon(
                FontAwesomeIcons.save,
                color: kThemeStyleButtonFillColour,
              )),
        ],
      ),
      body: ModalProgressHUD(
        inAsyncCall: showSpinner,
        child: SingleChildScrollView(
//          padding: EdgeInsets.only(top: 20.0),
          child: Form(
            autovalidateMode: AutovalidateMode.always,
            key: _formKey,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                LabelTextPadding(text: 'Business Information'),

                //business name
                RegularTextPadding(regText: 'Business Name'),
                _buildBusinessName(),
                SizedBox(height: 20.0),

                //business type
                RegularTextPadding(regText: 'Business Type'),
                Platform.isIOS
                    ? _buildCupertinoStyleBusinessType(context)
                    : _buildMaterialStyleBusinessType(context),

                //Trading currency
                RegularTextPadding(regText: 'Trading Currency'),
                Platform.isIOS
                    ? _buildCupertinoStyleTradingCurrency(context)
                    : _buildMaterialStyleTradingCurrency(context),

                //business location
                RegularTextPadding(regText: 'Location'),
                //address 1
                _buildAddress(),
                //city
                _buildCityField(),
                //postcode
                _buildPostcode(),
                //state
                _buildStateField(),
                //country
                Platform.isIOS
                    ? _buildCupertinoStyleCountry(context)
                    : _buildMaterialStyleCountry(context),

                SizedBox(
                  height: 20.0,
                ),
                DividerClass(),
                SizedBox(
                  height: 20.0,
                ),

                //Personal information
                LabelTextPadding(
                  text: 'Personal Information',
                ),
                _buildFirstNameField(),
                _buildLastNameField(),
                _buildPhoneNumberField(),
                // _buildEmailField(),

                //cancel and save buttons
                Padding(
                  padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      Buttons(
                          onPressedButton: () {
                            Navigator.pop(context);
                          },
                          buttonLabel: 'Cancel',
                          buttonColour: kThemeStyleButtonFillColour,
                          buttonTextStyle: kThemeStyleButton),
                      SizedBox(
                        width: 15.0,
                      ),
                      Buttons(
                          onPressedButton: () => _saveUserData(),
                          buttonLabel: 'Save',
                          buttonColour: kThemeStyleButtonFillColour,
                          buttonTextStyle: kThemeStyleButton),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  //business information
  Widget _buildBusinessName() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.businessName,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.businessName = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration:
            kTextFieldDecoration.copyWith(hintText: 'update business Name'),
      ),
    );
  }

  //business type - cupertino and material styles
  _buildCupertinoStyleBusinessType(BuildContext context) {
    return GestureDetector(
      child: Container(
        decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(5.0)),
            border: Border.all(
              color: kThemeStyleButtonFillColour,
              width: 1,
            )),
        padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
        margin: EdgeInsets.all(20.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(selectedBusinessTypeDropDownValue),
            Icon(
              FontAwesomeIcons.caretDown,
              color: kThemeStyleButtonFillColour,
            ),
          ],
        ),
      ),
      onTap: () => showModalBottomSheet(
        context: context,
        builder: (BuildContext builder) {
          return Container(
            color: Colors.white,
            height: MediaQuery.of(context).copyWith().size.height / 4,
            child: CupertinoPicker(
              magnification: 1.5,
              children: List<Widget>.generate(businessType.length, (int index) {
                return Center(
                  child: Text(
                    businessType[index].toString(),
                    softWrap: true,
                    style: TextStyle(fontSize: 15.0),
                  ),
                );
              }),
              itemExtent: 25,
              onSelectedItemChanged: (index) {
                setState(() {
                  selectedBusinessTypeDropDownValue = businessType[index];
                });
              },
            ),
          );
        },
      ),
    );
  }

  _buildMaterialStyleBusinessType(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
          border: Border.all(
            color: kThemeStyleButtonFillColour,
            width: 1,
          )),
      margin: EdgeInsets.all(20.0),
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: DropdownButton(
          value: _currentLoggedInUserData.businessType == null
              ? selectedBusinessTypeDropDownValue
              : _currentLoggedInUserData.businessType,
          elevation: 15,
          iconDisabledColor: kThemeStyleButtonFillColour,
          iconEnabledColor: kThemeStyleButtonFillColour,
          underline: Container(),
          items: businessType
              .map(
                (businessType) => DropdownMenuItem(
                    value: businessType, child: Text(businessType)),
              )
              .toList(),
          onChanged: (newValue) {
            setState(() {
              selectedBusinessTypeDropDownValue = newValue;
              _currentLoggedInUserData.businessType = newValue;
            });
          },
        ),
      ),
    );
  }

  //trading currency - cupertino and material styles
  _buildCupertinoStyleTradingCurrency(BuildContext context) {
    return GestureDetector(
      onTap: () => showModalBottomSheet(
        context: context,
        builder: (BuildContext builder) {
          return Container(
            color: Colors.white,
            height: MediaQuery.of(context).copyWith().size.height / 4,
            child: CupertinoPicker(
              magnification: 1.5,
              children:
                  List<Widget>.generate(tradingCurrency.length, (int index) {
                return Center(
                  child: Text(
                    tradingCurrency[index].toString(),
                    softWrap: true,
                    style: TextStyle(fontSize: 15.0),
                  ),
                );
              }),
              itemExtent: 25,
              onSelectedItemChanged: (index) {
                setState(() {
                  selectedCurrencyDropDownValue = tradingCurrency[index];
                });
              },
            ),
          );
        },
      ),
      child: Container(
        decoration: BoxDecoration(
            borderRadius: BorderRadius.all(Radius.circular(0.5)),
            border: Border.all(
              color: kThemeStyleButtonFillColour,
              width: 1,
            )),
        padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
        margin: EdgeInsets.all(20.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(selectedCurrencyDropDownValue),
            Icon(
              FontAwesomeIcons.caretDown,
              color: kThemeStyleButtonFillColour,
            ),
          ],
        ),
      ),
    );
  }

  _buildMaterialStyleTradingCurrency(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5.0),
          border: Border.all(
            color: kThemeStyleButtonFillColour,
            width: 1,
          )),
      margin: EdgeInsets.all(20.0),
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: DropdownButton(
          value: _currentLoggedInUserData.businessType == null
              ? selectedCurrencyDropDownValue
              : _currentLoggedInUserData.businessTradingCurrency,
          icon: Icon(
            FontAwesomeIcons.caretDown,
            color: kThemeStyleButtonFillColour,
          ),
          elevation: 15,
          underline: Container(
            color: kThemeStyleButtonFillColour,
          ),
          items: tradingCurrency
              .map(
                (tradingCurrency) => DropdownMenuItem(
                    value: tradingCurrency, child: Text(tradingCurrency)),
              )
              .toList(),
          onChanged: (newValue) {
            setState(() {
              selectedCurrencyDropDownValue = newValue;
              _currentLoggedInUserData.businessTradingCurrency = newValue;
            });
          },
        ),
      ),
    );
  }

  //address field
  _buildAddress() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.streetAddress,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.streetAddress = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration:
            kTextFieldDecoration.copyWith(hintText: 'house and street address'),
      ),
    );
  }

  //city field
  _buildCityField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.city,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.city = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter city'),
      ),
    );
  }

  //postcode field
  _buildPostcode() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.postcode,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.postcode = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter postcode'),
      ),
    );
  }

  //state field
  _buildStateField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.state,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.state = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'enter state'),
      ),
    );
  }

  //country field - cupertino and material styles
  _buildCupertinoStyleCountry(BuildContext context) {
    return GestureDetector(
      onTap: () => showModalBottomSheet(
        context: context,
        builder: (BuildContext builder) {
          return Container(
            color: Colors.white,
            height: MediaQuery.of(context).copyWith().size.height / 4,
            child: CupertinoPicker(
              magnification: 1.5,
              children: List<Widget>.generate(country.length, (int index) {
                return Center(
                  child: Text(
                    country[index].toString(),
                    softWrap: true,
                    style: TextStyle(fontSize: 15.0),
                  ),
                );
              }),
              itemExtent: 25,
              onSelectedItemChanged: (index) {
                setState(() {
                  selectedCountryDropDownValue = country[index];
                });
              },
            ),
          );
        },
      ),
      child: Container(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(0.5)),
          border: Border.all(
            color: kThemeStyleButtonFillColour,
            width: 1,
          ),
        ),
        padding: const EdgeInsets.fromLTRB(10.0, 12.0, 20.0, 12.0),
        margin: EdgeInsets.all(20.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(selectedCountryDropDownValue),
            Icon(
              FontAwesomeIcons.caretDown,
              color: kThemeStyleButtonFillColour,
            ),
          ],
        ),
      ),
    );
  }

  _buildMaterialStyleCountry(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(5.0),
        border: Border.all(
          color: kThemeStyleButtonFillColour,
          width: 1,
        ),
      ),
      margin: EdgeInsets.all(20.0),
      width: MediaQuery.of(context).size.width,
      child: Center(
        child: DropdownButton(
          value: _currentLoggedInUserData.country == null
              ? selectedCountryDropDownValue
              : _currentLoggedInUserData.country,
          elevation: 15,
          iconDisabledColor: kThemeStyleButtonFillColour,
          iconEnabledColor: kThemeStyleButtonFillColour,
          underline: Container(),
          items: country
              .map(
                (country) =>
                    DropdownMenuItem(value: country, child: Text(country)),
              )
              .toList(),
          onChanged: (newValue) {
            setState(() {
              selectedCountryDropDownValue = newValue;
              _currentLoggedInUserData.country = newValue;
            });
          },
        ),
      ),
    );
  }

  //logged in user personal info build
  //first name
  _buildFirstNameField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.firstName,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.firstName = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'your first Name'),
      ),
    );
  }

  //last name
  _buildLastNameField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.lastName,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.lastName = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration: kTextFieldDecoration.copyWith(hintText: 'your last name'),
      ),
    );
  }

  //phone number
  _buildPhoneNumberField() {
    return Container(
      padding: EdgeInsets.all(20.0),
      child: TextFormField(
        initialValue: _currentLoggedInUserData.phoneNumber,
        textAlign: TextAlign.left,
        onSaved: (value) {
          _currentLoggedInUserData.phoneNumber = value;
        },
        validator: TextInputFieldValidator.validate,
        decoration:
            kTextFieldDecoration.copyWith(hintText: 'your phone number'),
      ),
    );
  }
}

class TextInputFieldValidator {
  static String validate(String value) {
    if (value.isEmpty) {
      return 'This field can\'t be empty, you must enter a text';
    }
    if (value.length < 3) {
      return 'You must enter at least a word';
    }
    return value;
  }
}
4

0 回答 0